2012-12-22 21 views
1

我正在使用信號量來強制在我的程序中執行一些命令:我有一個主線程和一些在主線程中創建的子線程。 在每個步驟的主線程中打勾了一個時鐘,之後我希望每個子線程一個接一個地運行。子線程的順序並不重要,但我希望它們都在每一步中運行(並且每一步中只運行一次)。 我已經寫過這段代碼,但問題是,在某些情況下,在一些子線程上運行幾次而不讓別人有機會運行?!如何在java中的信號量中強制排序

主線:

 Semaphore okToTick = new Semaphore(3); 
    Semaphore okToWork = new Semaphore(0, true); 

    int i = 0; 

    new TestClass2(0, okToTick, okToWork); 
    new TestClass2(1, okToTick, okToWork); 
    new TestClass2(2, okToTick, okToWork); 

    while(true){ 

     okToTick.acquire(3); 

     System.out.printf("\clock : %s\n", i++); 


     okToWork.release(3); 

    } 

和子線程的run():

semaphores here, passed by cnstr() 
    ID = //passed in by cnstr()  
    isBusy = false; 
    ---------------------------------- 
    try{ 
     while(true){ 

      okToWork.acquire(); 

      if(!isBusy){ 
       System.out.println("inside sub " + ID); 
       isBusy = true; 
      } 


      okToTick.release(); 

     } 

    } 
    catch(Exception e){} 

我想這樣的結果:

clock : 0 
    inside sub 1 
    inside sub 0 
    inside sub 2 

    clock : 1 

    clock : 2 
    ... 

但有時我得到這個:

clock : 0 
    inside sub 1 

    clock : 1 
    inside sub 0 
    inside sub 2 

    clock : 2 
    ... 
+0

提示:當您釋放okToTick時,時鐘可能會打勾。而且,由於您在打印後立即發佈,時鐘有時會立刻出現並不奇怪。您需要等待所有子線程完成後再說可以打勾。祝你的作業好運。 – Hjalmar

+0

如果您有要按特定順序執行的任務,則應該在同一個線程中執行全部任務。如果您有多個可以按任意順序執行的獨立任務,則多個線程很有用。 –

回答

6

我認爲你正在尋找一個CyclicBarrier

一個同步輔助類,它允許一組線程都等待對方達成一個共同的障礙點。 CyclicBarriers在涉及固定大小的線程的程序中很有用,它必須偶爾等待對方。該屏障稱爲循環,因爲它可以在等待線程釋放之後重新使用。

+0

我不熟悉這個話題。是否可以僅使用信號量來完成這項工作? – msn

+5

您正在使用錘子來驅動螺絲。你爲什麼不學習如何使用螺絲刀。這是記錄,我甚至鏈接到javadoc。點擊,閱讀,理解並嘗試一些東西。如果你只想使用信號量,我會在每個工作線程中使用一個信號量。 –

+0

你是對的,但我必須在明天之前完成。正如我理解使用CyclicBarrier你必須使用一個實現可運行的類,但我不得不使用Thread的run方法。你能告訴我關於如何使用信號量來實現這個嗎?每個工作線程使用一個信號量意味着什麼? – msn

0

問題是您的「子線程」可能從信號量獲取多個許可證,並且您沒有在輸出中實現它,因爲「內部子」輸出只會打印一次(您會多次看到它,如果你刪除圍繞它的if(!isBusy))。如果您不希望每個「子線程」獲取多個許可證,請刪除外部的while(true)循環。

okToWork.acquire(); 

    //if(!isBusy){ Removed to show when this sub-thread is actually acquiring permits 
     System.out.println("inside sub " + ID); 
    // isBusy = true; 
    //} 


    okToWork.release(); 
+0

謝謝你的回覆。即使我仍然存在這個問題,我也會刪除它。在某些情況下,一個線程在一個tick中運行幾次!我必須在子線程中有循環。這只是程序的一部分。線程應該運行在一個循環中。 – msn

1

在你的情況下,一個線程可以獲取okToWork和其他人之前釋放okToTick多次,甚至有機會旋轉起來,即得。線程號1可以做到最多3次okTowork.acquire() - >okToTick.release()之前。

您還爲每個線程打印inside sub x一次,因爲您永遠不會重置isBusy標誌。

您需要區分它們,使用Semaphore的最簡單方法是爲每個線程提供不同的okToTick Semaphore