2017-05-07 56 views
0

你能描述一下在多線程環境下,下面的代碼工作不正確嗎?我從https://www.javacodegeeks.com/2014/11/multithreading-concurrency-interview-questions-answers.html獲取了代碼。說明說2個線程可能會一個接一個地進入第二個同步塊。這怎麼會發生?有兩個同步塊是什麼關係?2個線程如何能夠同時訪問同步塊?

public Integer getNextInt() { 
    Integer retVal = null; 
    synchronized (queue) { 
     try { 
      while (queue.isEmpty()) { 
       queue.wait(); 
      } 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
    synchronized (queue) { 
     retVal = queue.poll(); 
     if (retVal == null) { 
      System.err.println("retVal is null"); 
      throw new IllegalStateException(); 
     } 
    } 
    return retVal; 
} 

回答

1

這很簡單 - 第一個同步塊(S1)讓一個線程等待,直到隊列變爲非空。第二個同步塊(S2)使單個線程從隊列中取出一個項目。

  1. 線程1進入S1。
  2. 線程1存在S1 - >隊列不爲空
  3. 線程2進入S1
  4. 線程2存在S1 - >隊列仍然是不爲空
  5. 線程1進入S2 - >需要一個項目從隊列和它變空
  6. 線程1存在S2
  7. 線程2進入S2->嘗試從隊列中取一個元素,但它是空的 - >拋出異常。

正如你所看到的,只有一個線程按預期進入一個同步塊,但是這並不能保證正確的同步。

0

使用同步塊的整點是創建必須一起執行的「事務」周圍的代碼段; 沒有另一個線程進入「之間」的機會。

你的例子有兩個塊;並且很可能第一個線程離開第一個程序段;但在第一個線程可以進入第二個塊之前,第二個線程將會啓動。

這就是這一切。

0

queue.wait()釋放鎖,該鎖應用於同步塊。換句話說,當達到queue.wait()時,其他線程可以自由進入同步塊。下面我包含一個工作示例,其中5個線程同時進入同一個同步塊。您可以檢查此代碼以獲得一個感覺wait()和notiy()/ notifyAll()方法的工作原理:

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

     Runnable r =() -> { 
      System.out.println(" ThreadID: " + Thread.currentThread().getId() + " has started"); 
      synchronizedBlockExecution(); 
     }; 

     for (int i = 0; i < 5; i++) { 
      Thread t = new Thread(r); 
      t.start(); 
     } 

     Thread.sleep(1000); 
     System.out.println("------all threads are notifed to stop waiting!---------"); 
     synchronized (lock) { 
      lock.notifyAll(); 
     } 

    } 

    public static void synchronizedBlockExecution() { 
      System.out.println("Thread: " + Thread.currentThread().getId() + " is entering synchronized block"); 
      synchronized (lock) { 
       try { 
        lock.wait(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
      System.out.println("Thread: " + Thread.currentThread().getId() + " has left synchronized block"); 
    } 
} 
0

T1進入S1
T1存在S1
T2等待T1從S1完成
T1完成並進入S2
S1對於T2是空閒的
T2進入S1
以這種方式,T1和T2一次可以在兩個不同的同步塊中。這會提高性能。程序員應該寫同步塊而不是方法,因爲它允許兩個線程同時在兩個單獨的塊中工作。