2012-03-12 160 views
0

我需要一些幫助,以確保我理解同步塊。假設下面的例子:Java線程:同步塊

public class ThreadStarter { 
    public static void main(String[] args) { 

     Queue queueObject = new Queue(); 

     ThreadA thread1 = new ThreadA(queueObject); 
     ThreadA thread2 = new ThreadA(queueObject); 

     ThreadB thread3 = new ThreadB(queueObject); 
     ThreadB thread4 = new ThreadB(queueObject); 

     thread1.start(); 
     thread2.start(); 

    } 
} 

public class Queue { 

    Object[] the theQueue; 

    public Queue(int size){ 
     theQueue = new Object[size]; 
    } 

    public submitObject(Object o){ 
     /* add Object to the queue */ 
    } 

    public deleteObject(int objectId){ 
     /*delete Object from the queue */ 
    } 
} 

public class ThreadA extends Thread { 

    private Queue queue; 

    public ThreadA(Queue queue){ 
     this.queue = queue; 
    } 

    public void run() { 
     while(!isInterrupted()){ 
      synchronized(queue) { 
       Object o = new Object 
       queue.submitObject(o); 
       /* do some other stuff */ 
     } 

     try { 
      sleep((int)(Math.random()*1000)); 
     } catch (interruptedException) { 
      Thread.currentThread().interrupt; 
     } 

      synchronized(queue) { 
       /* do some other stuff on the queue */ 
      } 
     } 
    } 
} 

public class ThreadB extends Thread { 

    private Queue queue; 

    public ThreadB(Queue queue){ 
     this.queue = queue; 
    } 

    public void run() { 
     while(!isInterrupted()){ 
      synchronized(queue) { 
       queue.deleteObject(o); 
       /* do some other stuff */ 
     } 

     try { 
      sleep(1000); 
     } catch (interruptedException) { 
      Thread.currentThread().interrupt; 
     } 
    } 
} 
} 

我的問題是,它足以同步ThreadA中的整個隊列對象提交的目標隊列類,是在安全方面?我在ThreadB中做了同樣的操作,從隊列中刪除一個對象。或者,我還必須同步Queue類中的submitObject()和deleteObject()方法嗎?

在我的理解中,如果我像上面顯示的那樣鎖定了線程中的整個隊列類,我應該保持安全 - 對吧?

greetZ並提前致謝。

回答

2

所有你需要做的是確保沒有兩個線程不能同時進入submitObject & deleteObjecct。要做到這一點,只需聲明這些方法是同步的。 在這種情況下,類之間共享的隊列對象將阻止2個線程在同步的塊上進行。

如果你願意,而且有某種閉鎖機制,如:

「如果一個線程想刪除一個對象,它必須等待,如果有 沒有這樣的一個對象隊列。」

,那麼你需要做的不僅僅是同步這種方式更多:這兩種方法應該還是同步的,但進入DeleteObject的線程應該使用this.wait由隊列停止,直到有一個對象變爲可用:

public synchronized deleteObject() { 
    while(isEmpty()) { 
    try { 
     wait(); 
    } catch(Exception ex) { 
     ex.printStackTrace(); 
    }//catch 
    }//while 

    //actually do delete object. 
    ... 
}//met 

然後submitObject應該做通知等待狀態線程:

public synchronized submitObject() { 
    //do put object 
    ... 
    notifyAll(); 
}//met 

,你也可以穿越的角色和在兩種方法中添加一些代碼,在立場,允許提交者在隊列已滿時被阻止,並在隊列中剩餘一些空間時通知。

1

我會在submitObjectdeleteObject方法隊列對象上同步,這應該是足夠的,這意味着:

public submitObject(Object o){ 
    synchronized (theQueue) { 
     ... 
    } 
} 

public deleteObject(int objectId){ 
    synchronized (theQueue) { 
     ... 
    } 
} 
1

你要做的就是相當於同步方法(public synchronized method()this同步這是您的queue局部變量),只是必須記住每次使用隊列時都需要執行此操作。同步提交和刪除方法會更安全.... 它也會從同步塊中刪除Object o = new Object()

+0

+1:你封裝同步的越多,它越容易和安全。 – 2012-03-12 19:43:39

+1

它在功能上並不等同於「隊列」的方法。如果他這樣做了,那麼在每個'synchronized'部分找到的'/ *'還有一些其他的東西* /'不會處於關鍵部分並且可以並行運行。根據代碼的內容,這對同步也很重要。這與同步列表很相似:如果你想以原子方式執行多個操作(例如遍歷它),你仍然需要在列表上進行外部同步。 – 2012-03-12 20:00:58

+0

@MaxPeters完全同意。 – assylias 2012-03-12 20:02:12