Java 应该在列表本身上同步还是在锁对象上同步?

Java 应该在列表本身上同步还是在锁对象上同步?,java,synchronization,synchronized,Java,Synchronization,Synchronized,一段时间以来,我一直在思考一个问题:当多个线程可以访问一个列表(ArrayList…)时,同步对该列表的访问如何更安全?在列表上同步更安全,还是创建锁对象并使用它在列表上同步更安全?无需自行同步。集合框架已经做到了。好好利用它 List list = Collections.synchronizedList(yourList); 并使用返回的列表。记住这个方法 返回由指定列表支持的同步(线程安全)列表 只要您的锁对象是最终的,两者在安全性方面是等效的。如果在代码中的多个类上访问列表,那么锁定该

一段时间以来,我一直在思考一个问题:当多个线程可以访问一个列表(ArrayList…)时,同步对该列表的访问如何更安全?在列表上同步更安全,还是创建锁对象并使用它在列表上同步更安全?

无需自行同步。集合框架已经做到了。好好利用它

List list = Collections.synchronizedList(yourList);
并使用返回的
列表
。记住这个方法

返回由指定列表支持的同步(线程安全)列表


只要您的锁
对象
最终的
,两者在安全性方面是等效的。如果在代码中的多个类上访问
列表
,那么锁定该列表本身可能会更容易,因此,您不必同时传递正在同步的
列表
对象

但是您应该避免所有这些,让Java通过使用
列表=集合来处理同步。synchronizedList(新ArrayList)
我相信这就是您想要的。可能有2种情况(最终):

使用单独的锁进行同步。

someMethod(){
synchronized(lock){
// code to access/modify List here
}
}
您可以直接在列表实例上同步

synchronized(list)
{
// code to access/modify list here
}
如果
someMethod()
是访问列表的唯一方法,则第一种情况是安全的。来自不同流的任何其他线程都可以修改实际列表


第二种情况锁定实际的列表实例,因此,始终保证一次只有一个线程访问/修改列表。

只要始终锁定对象,这两个选项或多或少都是等效的。因此,列表上的同步本身可能更无错误,因为您不能意外地使用“其他对象”进行同步

如前所述,如果只需要“简单”同步,则可以使用
syncList=Collections.synchronizedList(yourList)
。。。这将是最安全的方法,但在更一般的同步场景中,如“不存在时放入”等,这是不够的。例如,以下被剪断的是坏的-不够同步:

if (syncList.contains(element)) { syncList.add(element); }

谢谢回复,但我知道Collections.synchronizedList。我不是指那个,只是指什么是最佳实践,两者中的最佳选择。@JohnyX我通常将类的基本部分同步,而不是将整个对象作为lock:)@sᴜʀᴇsʜᴀᴛᴛᴀ - 对考虑到一个事实,即在同步块中不能保证在之前发生:)让我们以列表本身的同步为例。是否存在这样的情况:某个线程可以修改列表的内容,因此在执行第二次锁定时,我不会拥有相同的列表对象?Thanks@JohnyX-否。一次只能有一个线程访问该列表实例。您将锁定列表实例。由另一个线程创建/返回的任何新对象都不会使其他线程锁定新列表对象。它们仍将锁定在相同的旧列表对象上。