【问题标题】:Multithreading on different objects' lock不同对象锁上的多线程
【发布时间】:2016-03-21 08:00:25
【问题描述】:

我是 Java 编程的新手,我知道多线程在 Java 中不是一个微不足道的话题,而且我作为 C 开发人员工作了近 3 年。

我读过这个话题:“Multiple locks - Behind the scene”,我完全理解,但我有一个顾虑。

我更新代码如下:

package multithreading;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Worker {

    private List<Integer> list1 = new ArrayList<Integer>();
    private List<Integer> list2 = new ArrayList<Integer>();

    private Object lock1 = new Object();
    private Object lock2 = new Object();

    private void updateList1(int i) {
        synchronized (lock1) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException ex) {
                Logger.getLogger(Worker.class.getName()).log(Level.SEVERE, null, ex);
            }
            list1.add(1);
        }
    }

    private void updateList2(int i) {
        synchronized (lock2) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException ex) {
                Logger.getLogger(Worker.class.getName()).log(Level.SEVERE, null, ex);
            }
            list2.add(1);
        }
    }

    public void process(int ii) {
        for (int i = 0; i < 1000; i++) {
            updateList1(ii);
            updateList2(ii);
        }
    }

    public void execute() {
        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                process(1);
            }
        });

        Thread t2 = new Thread(new Runnable() {

            @Override
            public void run() {
                process(2);
            }
        });

        long start = System.currentTimeMillis();

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException ex) {
            Logger.getLogger(Worker.class.getName()).log(Level.SEVERE, null, ex);
        }

        long end = System.currentTimeMillis();

        System.out.println("Time taken: " + (end - start));
        System.out.println("List1: " + list1.size() + "; list2: " + list2.size());
    }
}

在主类中我创建了一个对象并调用了execute方法,输出是:

Time taken: 2186 List1: 2000; list2: 2000

但是,如果我将两个函数(updateList1、updateList2)都设为synchronized 并删除了lock1lock2 上的同步块

主会输出:

Time taken: 4342 List1: 2000; list2: 2000

问题是execute() 中的代码调用updateList1() 然后updateList2() 所以这是对这两种方法的顺序调用,在第一个代码中(使用synchronized 块)如果一个线程获取lock1 和试图调用updateList1() 的另一个线程将等待另一个线程释放lock1。所以两种实现方式的时间必须相等。

如果我在 Java 中理解有任何错误,请纠正答案,抱歉,因为这种情况是我从 C 语言经验中了解到的。

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    对于同步方法,在任何给定时间只能执行两种方法中的一种。这会导致如下的顺序执行(当然还有许多其他可能性):

    t1: updateList1             updateList2
    t2:             updateList1             updateList2
    

    在不同的锁对象上使用同步语句,允许两种方法同时运行。

    t1: updateList1 updateList2 updateList1 updateList2 
    t2:             updateList1 updateList2 updateList1
    

    在初始步骤之后updateList1updateList2 可以并行运行。由于这些方法需要相同的时间,因此在第二种情况下,您还可以获得 2 倍的理想加速。

    【讨论】:

      【解决方案2】:

      时间不一样,因为在您使updateList1updateList2 同步的情况下,它们使用Worker 对象作为锁实例。

      那么在第二种情况下,如果一个线程正在运行updateList2,则另一个线程无法进入updateList1

      【讨论】:

        【解决方案3】:
        • 对于第一种情况,没有应用锁,因为锁定的对象 有区别。
        • 对于第二种情况,您删除了锁定对象, 然后,锁对象现在来到了Test的实例,它 包含 list1 和 list2。在这种情况下,当测试同步时 被 Thread1 访问,Thread2 需要等待,反之亦然。

        【讨论】:

          猜你喜欢
          • 2014-12-01
          • 2017-11-05
          • 1970-01-01
          • 1970-01-01
          • 2011-03-07
          • 2020-10-31
          • 1970-01-01
          • 2023-03-19
          • 1970-01-01
          相关资源
          最近更新 更多