同步非最终列表

时间:2013-05-09 18:57:38

标签: java synchronized

好的,据我了解,最好创建一个用于同步的final static对象。

但是,我还读到,如果对象引用没有改变,那么它就不会出现并发问题。

以下代码是否违反了同步性?

class Foo {
    private static ArrayList<Client> clients = null;

    public Foo() {
        clients = new ArrayList<>();
        //add stuff to list here..
    }

    public void addClient(Client C) {
        synchronized(clients) {
            clients.add(C);
        }
    }
}

如果客户端ArrayList从未直接暴露(仅通过Getters),我是否必须使客户端最终或创建最终对象?换句话说,我从不为clients数组提供set方法,因此引用永远不会改变。

3 个答案:

答案 0 :(得分:3)

任何创建Foo new Foo()实例的人都会覆盖clients数组。它肯定不是线程安全的

答案 1 :(得分:2)

如果您真的希望客户端是静态的,即所有Foos共享一个客户端列表,以便收集所有客户端的大量列表,那么您只需要初始化一次。

private static ArrayList<Client> clients = new ArrayList();

但是我怀疑你想要每个Foo有一个客户端列表,在这种情况下,将其声明为静态,为了清晰,请将其声明为final。 (还有一些奇怪的极端情况,你真的必须将它声明为final,如Java Concurrency in Practice中所述。)

答案 2 :(得分:1)

要使其线程安全,请更改“客户端”的声明,如下所示:

private final static List<Client> clients = new ArrayList<Client>();

并像你一样使用'synchronized'。

如果您对static关键字的含义感到困惑: static关键字意味着将为所有Foo实例共享“clients”的相同实例。如果删除static关键字,每个Foo实例都将拥有它自己的'clients'实例。

final关键字只会阻止您重新分配clients变量。