我正在尝试使用两个线程将 String
值添加到 ArrayList
。我想要的是,当一个线程添加值时,另一个线程不应该干扰,所以我使用了 Collections.synchronizedList
方法。但似乎如果我没有在对象上显式同步,则添加是以非同步方式完成的。
没有显式同步块(synchronized block):
public class SynTest {
public static void main(String []args){
final List<String> list=new ArrayList<String>();
final List<String> synList=Collections.synchronizedList(list);
final Object o=new Object();
Thread tOne=new Thread(new Runnable(){
@Override
public void run() {
//synchronized(o){
for(int i=0;i<100;i++){
System.out.println(synList.add("add one"+i)+ " one");
}
//}
}
});
Thread tTwo=new Thread(new Runnable(){
@Override
public void run() {
//synchronized(o){
for(int i=0;i<100;i++){
System.out.println(synList.add("add two"+i)+" two");
}
//}
}
});
tOne.start();
tTwo.start();
}
}
我得到的输出是:
true one
true two
true one
true two
true one
true two
true two
true one
true one
true one...
在未注释显式同步块(synchronized block)的情况下,我将在添加时停止来自其他线程的干扰。一旦线程获得了锁,它就会一直执行直到完成。
取消注释同步块(synchronized block)后的示例输出:
true one
true one
true one
true one
true one
true one
true one
true one...
那么为什么 Collections.synchronizedList()
没有进行同步呢?
最佳答案
同步列表仅同步该列表的方法。
这意味着当另一个线程当前正在运行此列表中的方法时,一个线程将无法修改该列表。对象在处理方法时被锁定。
例如,假设有两个线程在您的列表上运行 addAll
,有 2 个不同的列表(A=A1,A2,A3
和 B=B1 ,B2,B3
) 作为参数。
由于方法是同步的,你可以确定这些列表不会像
A1,B1,A2,A3,B2,B3
你不能决定一个线程何时将进程移交给另一个线程。每个方法调用都必须完全运行并返回,然后才能运行另一个。所以你可以得到
A1,A2,A3,B1,B2,B3
或B1,B2,B3,A1,A2,A3
(因为我们不知道哪个线程调用将首先运行)。
在您的第一段代码中,两个线程同时运行。两者都尝试将元素 add
到列表中。除了 add
方法上的同步之外,您没有任何方法可以阻止一个线程,因此没有什么可以阻止线程 1 在将进程移交给线程 2 之前运行多个 add
操作. 所以你的输出是完全正常的。
在您的第二段代码(未注释的代码)中,您明确声明一个线程在开始循环之前将列表与另一个线程完全锁定。因此,您要确保其中一个线程在另一个线程可以访问列表之前运行完整的循环。
关于java - Collections.synchronizedList() 方法有什么用?它似乎没有同步列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40930861/