两种定义线程安全类的方法之间的区别

时间:2016-09-01 06:02:52

标签: java multithreading collections synchronization

我想知道以下两个示例类中的功能差异。哪种风格应该优先于另一种风格以及为什么。

public class MyQueue {
    private Queue<Abc> q;

    public MyQueue() {
        q = Collections.synchronizedList(new LinkedList<Abc>());
    }

    public void put(Abc obj) {
        q.add(obj);
    }

    public Abc get() {
        return q.remove();
    }
}

OR

public class MyQueue {
    private Queue<Abc> q;

    public MyQueue() {
        q = new LinkedList<Abc>();
    }

    public synchronized void put(Abc obj) {
        q.add(obj);
    }

    public synchronized Abc get() {
        return q.remove();
    }
}

我的看法 - 就课堂上的这么多功能而言,两者都会完美无缺,只是个人喜好。

如果有更多不同,请告诉我。

2 个答案:

答案 0 :(得分:2)

The main architectural difference is that the second implementation exposes the synchronization monitor (the object itself) to the outside world. It means that everyone can potentially acquire the same lock you use for internal synchronization:

MyQueue myQueue = new MyQueue();  // a shared instance

synchronized(myQueue) {
    // No one else can call synchronized methods while you're here
}

It might bring benefits or cause problems depending on your class use cases.

The fact that the first implementation hides the details of synchronization gives you a bit more flexibility for adding new functionality in the future (for instance, you can add some not synchronized code into your put() and get() methods if you need), but comes with a minor penalty of having an additional layer around your list.

Otherwise, there's no difference given the presented functionality.

PS: Don't forget to add final to the q declaration. Otherwise your class doesn't guarantee so called safe publication and cannot be called fully thread-safe.

答案 1 :(得分:0)

如果是列表,则在通过包装器访问它或使用synchronized块保护对它的每次访问之间的功能上应该没有任何区别。

但是有一种情况是最好使用包装器提供的同步机制,就像ConcurrentHashMap一样。

例如,如果您要保护自己对简单的非线程安全HashMap的访问,则会锁定整个映射(所有键)以进行任何读/写,这将影响映射上的并发性。 ConcurrentHashMap仅锁定映射的键集,因此您可以使用它来进行读/写并发操作。

谢谢!