2013-06-21 36 views
2

當我們調用lock.lock()或者嘗試輸入​​塊時,如果其他線程已經佔用了該鎖,我們的線程將被阻塞。現在我的問題是,當我們查看lock.lock()的實現時,它將獲取鎖定委託給AQS,它實際上停留了當前線程(所以它不能被調度器進一步調度)。是否同步駐留像Lock.lock()這樣的併發線程?

是否與​​阻塞一樣?

我甚至覺得我的線程狀態也不同。例如,如果我的線程在​​塊上被阻止,則它將爲BLOCKING,而如果我已撥打 lock.lock(),則它將是WAITING。我對嗎?

我擔心的是,而不是忙碌等待

  1. ReentrantLock.lock();
  2. synchronize { /*some code */ }
+0

對不起,我回復自動翻譯。我認爲你應該附上一個示例代碼,這將幫助我們幫助你分析問題。一般情況下使用同步,不需要鎖定。鎖 ()。一般來說,足夠同步。 –

回答

4

攔截 - 被阻止上的資源,不能被中斷

等待 - 被阻止上的資源,但是可以中斷或通知或已啓動。

正如你所看到的WAITING更適合於從另一個處理過的控制。例如如果兩個線程死鎖,你可以用一箇中斷來破解鎖()。使用同步的兩個線程會卡住。

同步vs鎖的行爲非常相似,主要修訂之間的確切細節更改。

我的建議是使用

  • 同步的,你需要線程安全的,但有一個非常低鎖爭用簡單的代碼。

  • 使用鎖定您確定存在鎖定爭用的位置,或者您需要其他功能,例如tryLock。


如果你

final Lock lock = new ReentrantLock(); 
lock.lock(); 
Thread t = new Thread(new Runnable() { 
    @Override 
    public void run() { 
     try { 
      lock.lockInterruptibly(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
}); 
t.start(); 
Thread.sleep(100); 
System.out.println(t + " is " + t.getState()); 
lock.unlock(); 

打印

Thread[Thread-0,5,main] is WAITING 

Thread.State狀態


蘇氨酸等待線程的狀態。線程處於等待狀態,因爲調用下列方法之一:

  • 的Object.wait不帶超時
  • 的Thread.join沒有超時
  • LockSupport.park

一處於等待狀態的線程正在等待另一個線程執行特定操作。例如,一個在對象上調用Object.wait()的線程正在等待另一個線程調用該對象的Object.notify()或Object.notifyAll()。已調用Thread.join()的線程正在等待指定的線程終止。

+0

感謝@Peter Lawrey當線程阻塞lock.lock()時,線程的狀態是什麼?BLOCKING或WAITING – veritas

+0

好點,lock()將被阻塞,並且lockInterrupptably()將會等待,因爲它可能被中斷。 –

+0

@PeterLawrey調用鎖也將線程置於WAITING狀態 – linski

2

停車線程和同步之間的下面兩個鎖定策略和績效改進的Thread.status方面由停車場的區別阻塞是非常不同的。當您嘗試並輸入同步塊時,您明確嘗試獲取對象實例上的監視器。如果無法獲取顯示器,則線程將進入BLOCKING狀態,直到顯示器可用。停車更類似於Object.wait()方法,因爲代碼知道在其他條件成立之前它不能繼續。沒有意義阻止這裏,因爲這將是徒勞的,因爲我的繼續條件目前是正確的。此時我進入WAITING或TIMED_WAITING狀態(取決於等待狀態如何發出),直到通知我(通過類似notify()notifyAll()unpark())。一旦我的條件成爲現實,我會出來,如果我的等待狀態,然後可能試圖獲得監視器,並進入阻塞,如果我需要他們。如果我得到我的顯示器,我進入RUNNING並繼續我的快樂的方式

所以等待是真的關於知道我不能做某事,並有一些其他線程通知我,當它認爲我可以。我醒來後可能會導致阻塞。阻塞只是在沒有明確的其他先決條件的情況下競爭訪問監視器。

當在Lock實例上調用lock()時,調用線程實際上會進入等待狀態並且不會阻塞。這樣做的好處是這個等待狀態可以被中斷,這有助於避免死鎖。有了類似Lock的課程,您可以通過tryLock()tryLock(long,TimeUnit)lock()lockInterruptibly()獲得期望的等待行爲。你可以指定一些事情,比如你想等多久,以及你是否可以通過你打電話的方式來中斷。使用​​代碼,您沒有這樣的選項。你被阻塞了,你被阻塞了,直到某個線程放棄了你想要的顯示器,並且如果它永遠不會,你就會陷入僵局。這就是爲什麼從Java 5和concurrent包開始,您應該避免使用​​關鍵字,而是嘗試並實現類似的語義,如LockCondition

+0

感謝@cmbaxter,其實我想問的是,線程實際上去停車時,它調用Reentrantlock.lock()。這就是爲什麼我的問題是阻止在ReentrantLock.lock()實際上是不會阻止 – veritas

+0

更新我的答案... – cmbaxter

+0

謝謝@cmbaxter所以線程狀態將等待,然後 – veritas

3

籲請locklockInterruptibly會把線程WAITING狀態:

線程狀態的等待線程。線程處於等待狀態,因爲調用下列方法之一:

  • 的Object.wait不帶超時
  • 的Thread.join沒有超時
  • LockSupport.park

以下代碼啓動四個線程,前兩個(A,B)運行相同的代碼並通過lock方法鎖定某個監視器。其他兩個(C,d)還運行相同的代碼,但它們經由lockInterruptibly方法鎖定某些另一個監視器:

public static synchronized void dumpThreadState(List<Thread> threads) { 
    System.out.println("thread state dump start"); 
    for (Thread t: threads) { 
     System.out.println(t.getName()+" "+t.getState()); 
    } 
    System.out.println("thread state dump end\n"); 
} 

public static void main(String[] args) throws InterruptedException { 
    final Lock lock = new ReentrantLock(); 
    final Lock anotherLock = new ReentrantLock(); 
    List<Thread> threads = new LinkedList<Thread>(); 

    Runnable first = new Runnable() { 

     @Override 
     public void run() {     
      try { 
       lock.lock(); 
      } 
      catch (Exception ex) { 
       System.out.println(Thread.currentThread().getName()+" processing exception "+ex.getClass().getSimpleName());      
      } 
      while (true);     
     } 
    } ; 
    Runnable second = new Runnable() { 

     @Override 
     public void run() {   
      try { 
       anotherLock.lockInterruptibly(); 
      } 
      catch (InterruptedException ex) { 
       System.out.println(Thread.currentThread().getName()+" was interrupted"); 
      } 
      while (true); 
     } 
    }; 

    threads.add(new Thread(first,"A")); 
    threads.add(new Thread(first,"B")); 
    threads.add(new Thread(second,"C")); 
    threads.add(new Thread(second,"D")); 


    dumpThreadState(threads); 

    for (Thread t: threads) { 
     t.start(); 
    } 

    Thread.currentThread().sleep(100); 

    dumpThreadState(threads); 

    System.out.println("interrupting " + threads.get(1).getName()); 
    threads.get(1).interrupt(); 

    dumpThreadState(threads); 

    System.out.println("interrupting " + threads.get(3).getName()); 
    threads.get(3).interrupt(); 

    Thread.currentThread().sleep(100); 
    dumpThreadState(threads); 

    for (Thread t: threads) { 
     t.join(); 
    } 
} 

它輸出:

thread state dump start 
A NEW 
B NEW 
C NEW 
D NEW 
thread state dump end 

thread state dump start 
A RUNNABLE 
B WAITING 
C RUNNABLE 
D WAITING 
thread state dump end 

interrupting B 
thread state dump start 
A RUNNABLE 
B WAITING 
C RUNNABLE 
D WAITING 
thread state dump end 

interrupting D 
D was interrupted 
thread state dump start 
A RUNNABLE 
B WAITING 
C RUNNABLE 
D RUNNABLE 
thread state dump end 

正如可以看出鎖定螺紋通過lock方法不能中斷,而線程用lockInterruptibly鎖定即可。

在另一個示例中,啓動了三個線程,前兩個線程(A,B)運行相同的代碼並通過​​塊鎖定在同一監視器上。

public static void main(String[] args) throws InterruptedException { 
    final Object lock = new Object(); 
    final Object anotherLock = new Object(); 

    List<Thread> threads = new LinkedList<Thread>(); 

    Runnable first = new Runnable() { 

     @Override 
     public void run() { 
      synchronized(lock) { 
       while (true); 
      } 
     } 
    } ; 
    Runnable second = new Runnable() { 

     @Override 
     public void run() {   
      synchronized(anotherLock) { 
       try { 
        anotherLock.wait(); 
       } 
       catch (InterruptedException ex) { 
        ex.printStackTrace(); 
       } 
      } 
     } 
    }; 

    threads.add(new Thread(first,"A")); 
    threads.add(new Thread(first,"B")); 
    threads.add(new Thread(second,"C")); 

    dumpThreadState(threads); 

    for (Thread t: threads) { 
     t.start(); 
    } 

    Thread.currentThread().sleep(100); 

    dumpThreadState(threads); 

    for (Thread t: threads) { 
     t.join(); 
    } 

} 

它輸出:

thread state dump start 
A NEW 
B NEW 
C NEW 
thread state dump end 
thread state dump start 
A RUNNABLE 
B BLOCKED 
C WAITING 
thread state dump end 

線程C-結束了在WAITING狀態,同時線程B在BLOCKING狀態結束了:

另一個顯示器上的第三螺紋鎖而是經由 wait方法等待

線程阻塞等待監視器鎖定的線程狀態。處於阻塞狀態的線程正在等待監視器鎖定,以便在調用Object.wait之後輸入同步塊/方法或重新輸入同步塊/方法。

編輯:

這裏是線程狀態的一個真正的好UML diagram