好的,据我了解,最好创建一个用于同步的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方法,因此引用永远不会改变。
答案 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变量。