同步:多个锁 - 创建锁对象?

时间:2014-09-29 11:36:12

标签: java multithreading locking

一个快速的(我认为)并发问题:我正在Udemy.com上完成多线程课程,老师通过下面的代码进行了讨论。虽然他解释了这一点,但我仍然不确定为什么要创建lock1lock2个对象而不是锁定list1list2

App.java:

public class App {

    public static void main(String[] args) {
        Worker worker = new Worker();
        worker.main();
    }
}

Worker.java:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;


public class Worker {

    private Random random = new Random();

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

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

    public void stageOne() {

        synchronized (lock1) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            list1.add(random.nextInt(100));
        }

    }

    public void stageTwo() {

        synchronized (lock2) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            list2.add(random.nextInt(100));
        }

    }

    public void process() {
        for(int i=0; i<1000; i++) {
            stageOne();
            stageTwo();
        }
    }

    public void main() {
        System.out.println("Starting ...");

        long start = System.currentTimeMillis();

        Thread t1 = new Thread(new Runnable() {
            public void run() {
                process();
            }
        });

        Thread t2 = new Thread(new Runnable() {
            public void run() {
                process();
            }
        });

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

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        long end = System.currentTimeMillis();

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

1 个答案:

答案 0 :(得分:4)

我不认为你给出的代码表达了它的动机,但 通常是最佳做法。但是,同样的最佳实践要求锁定对象也是final

如果有问题的列表要么从外部接受,要么通过方法暴露给外部,那么单独的锁定对象的好处变得更加明显:将锁定暴露给外来代码永远不是一个好主意,因为外来代码然后可以单独使用它们来锁定,打破你自己的使用模式。

如果列表是严格私有的,那么它们的监视器可用于内部锁定;但是,稍后更改列表上的访问策略可能会无意中影响锁定策略。因此,从私有锁开始也可以避免任何未来的错误。