同步列表时的操作顺序

时间:2014-03-13 14:07:19

标签: java multithreading synchronization

我想了解Java在同步列表时的确切工作原理。 我们假设我有这个代码:

List list = Collections.synchronizedList(new ArrayList());

synchronized(list) {
      Iterator i = list.iterator();
      while (i.hasNext())
          foo(i.next());
}

并且线程(线程1)正在执行它。

另一个线程(线程2):

list.add(....)

而前一个代码正在线程1中执行。

线程2会等到线程1完成该代码吗?同步就像"等待另一个完成"?

或者,例如,如果3个线程到达synchronized(list) {}包裹的某些代码,它们是仅按顺序启动它,而不是同时启动它吗?

5 个答案:

答案 0 :(得分:4)

  

线程2会等到线程1完成该代码吗?,即syncronzying就像“等待另一个完成”?

如果某个线程获得了锁,那么在初始线程释放锁之前,没有其他线程可以获得相同的锁。

  

或者,例如,如果3个线程到达由synchronized(list){}包装的某些代码,它们是仅按顺序启动它,而不是同时启动它吗?

是,按顺序,但未指定订单。从您的角度来看,它可能是首先获得它的3个线程中的任何一个。

P.S。 Mutex获取(已同步)没有任何公平性。未指定哪个线程以及何时获取锁定。 例如:如果您拥有持有锁的线程A,并且还有其他3个线程正在等待相同的锁,并且线程A在一段时间后释放锁;那么 4个线程中的任何(包括线程A)都可以获取该锁

答案 1 :(得分:2)

如果查看Collections.synchronizedList后面的源代码,您会看到它创建Collections.SynchronizedList的实例,该实例使用设置为{{1的内部mutex进行锁定当没有传递其他值时。

您的代码会锁定this实例本身,因此在使用list时会起作用,但必须手动同步Collections.synchronizedList(List)才能避免使用List.iterator

答案 2 :(得分:1)

  
      
  1. 同步不在方法级别/代码级别。它处于对象级别。
  2.   
  3. 如果要同步对象,则访问该对象的任何线程必须首先锁定对象的监视器。
  4.   
  5. 如果thread1在监视器上有锁定,则尝试访问该对象的任何其他线程都必须等到thread1释放锁定。
  6.   

答案 3 :(得分:1)

在您的示例中,线程2将等待,因为线程1已获取同步列表上的锁定。

一般来说,同步块中包含的代码完全在同一个Object上的“下一个”同步块之前执行。

答案 4 :(得分:1)

Java中的同步是合作的,而不是强制性的。我的意思是,您希望同步保护数据,但该语言只允许您同步操作数据的代码块。您有责任确保所有可以触及您数据的代码都是同步的。

(这是其他一些答案的含义,当他们说,"同步是代码级别,而不是对象级别。)

在您的示例中,您编写了一个操作列表的同步代码块。这将阻止两个或多个线程同时进入那个代码块,但它通常不会阻止其他线程从其他代码块中同时操作列表,即使一个线程在同步块。

另请注意:监视器对象(您同步的对象)不必是您尝试保护的数据的一部分。例如,您可以有两个列表;并且您可能希望保证两个列表之间的某种关系(例如,两者必须是相同的长度)。在那种情况下,您同步哪个列表?答案可能都不是。如,

private Object lock = new Object();
private List<Foo> fooList = ...;
private List<Bar> barList = ...;

... doSomethingFascinating(...) {
    synchronized(lock) {
        //Use your shameful imagination here.
    }
}