Collections.synchronizedList()方法有什么用? 它似乎没有同步列表

我试图使用两个线程将String值添加到ArrayList 。 我想要的是,当一个线程添加值时,另一个线程不应该干扰,所以我使用了Collections.synchronizedList方法。 但似乎如果我没有在对象上显式同步,则以不同步的方式完成添加。

没有显式同步块:

 public class SynTest { public static void main(String []args){ final List list=new ArrayList(); final List 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块后的示例输出:

 true one true one true one true one true one true one true one true one... 

那么为什么Collections.synchronizedList()没有进行同步?

同步列表仅同步此列表的方法。

这意味着当另一个线程当前正在运行此列表中的方法时,线程将无法修改列表。 处理方法时对象被锁定。

举个例子,假设有两个线程在你的列表中运行addAll ,有2个不同的列表( A=A1,A2,A3B=B1,B2,B3 )作为参数。

  • 由于方法是同步的,您可以确定这些列表不会像A1,B1,A2,A3,B2,B3那样随机合并

  • 您不确定线程​​何时将进程切换到另一个线程,因此您可以获得A1,A2,A3,B1,B2,B3B1,B2,B3,A1,A2,A3

在第一段代码中,两个线程同时运行。 两者都试图在列表中add一个元素。 你没有办法阻止除了add方法上的同步之外的一个线程,所以没有什么能阻止线程1在将进程交给线程2之前运行多个add操作。所以你的输出是完全正常的。

在你的第二段代码(未注释的代码)中,你清楚地说明一个线程在开始循环之前完全锁定了另一个线程的列表。 因此,您确保您的某个线程将在另一个线程可以访问该列表之前运行完整循环。

Collections.synchronizedList()将同步对支持列表的所有访问,除非迭代时仍需要在同步块中以同步的List实例作为对象的监视器完成。

例如,这里是add方法的代码

 public boolean add(E e) { synchronized (mutex) {return c.add(e);} } 

这保证了对支持列表的串行访问,因此如果你的2个线程同时调用add ,一个线程将获取锁,添加其元素并释放锁,然后第二个线程将能够获取锁并添加其元素这就是为什么你在输出中得到onetwo

取消注释同步块时,代码就是

 synchronized(o) { for(int i=0;i<100;i++){ ... } } 

在这种情况下,首先可以获取锁定的线程将在释放锁之前执行整个 for循环(除非抛出exception),允许另一个线程执行其synchronized块的内容,这就是为什么你得到连续100onetwo然后连续100次另一次值。

可观察行为绝对正确 – 您在代码示例中演示的synchronized方法与synchronizedList 。 在第一种情况下,您同步整个for语句,因此只有一个线程将同时执行它。 在第二种情况下,您同步集合方法本身 – 这就是synchronizedList代表的含义。 所以请确保add方法是同步的 – 但不是for方法!