2012-11-22 55 views
0

我需要運行名爲ArrayHolder Java程序將運行兩個ThreadsArrayHolder將有一個ArrayThreadSeven將覆蓋的是Array 7,和ThreadOne每一個元素與1 執行後的結果應該是7,1,7,1,7,1,7,1等我解決了這個問題,但我不喜歡我的解決方案,並希望你可以建議一個更好的方法。同步的帖子 - 作業

P.S:兩個線程都必須在所有索引寫。

public class ArrayHolder { 

    private int[] array = {1, 2, 3, 4, 5, 6, 4, 8, 9, 10}; 

    public void writeInt(int pos, int num) { 
     array[pos] = num; 
    } 

    public static void main(String[] args) { 
     ArrayHolder holder = new ArrayHolder(); 
     ThreadSeven seven = new ThreadSeven(holder, null); 
     Runnable one = new ThreadOne(holder, seven); 
     Thread thread1 = new Thread(seven); 
     Thread thread2 = new Thread(one); 
     seven.setThread(one); 

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

     holder.printArray(); 
    } 

    private void printArray() { 
     for (int i = 0; i < 10; i++) { 
      System.out.println(array[i]); 
     } 
    } 

public class ThreadSeven implements Runnable { 
    private ArrayHolder array; 
    private Runnable t; 
    private int flag=0; 
    @Override 
    public void run() { 
     for(int i=0;i<10;i++){ 
      array.writeInt(i, 7); 

      flag=(flag+1)%2; 
      if (flag==0){ 
       synchronized(t){ 
        t.notify(); 
       } 
      }else{ 
       synchronized(this){ 
        try { 
         this.wait(); 
        } catch (InterruptedException ex) { 
         Logger.getLogger(ThreadSeven.class.getName()).log(Level.SEVERE, null, ex); 
        } 
       } 
      } 
     } 
    } 
    public ThreadSeven (ArrayHolder ar,Runnable t){ 
     array=ar; 
     this.t=t; 
    } 
    public void setThread(Runnable t){ 
     this.t=t; 
    } 
} 

public class ThreadOne implements Runnable { 

    private ArrayHolder array; 
    private Runnable t; 
    private int flag = 0; 

    @Override 
    public void run() { 
     for (int i = 0; i < 10; i++) { 
      array.writeInt(i, 1); 

      flag = (flag + 1) % 2; 
      if (flag == 1) { 
       synchronized (t) { 
        t.notify(); 
       } 
      } else { 
       synchronized (this) { 
        try { 
         this.wait(); 
        } catch (InterruptedException ex) { 
         Logger.getLogger(ThreadSeven.class.getName()).log(Level.SEVERE, null, ex); 
        } 
       } 
      } 
     } 
    } 

    public ThreadOne(ArrayHolder ar, Runnable t) { 
     array = ar; 
     this.t = t; 
    } 

    public void setThread(Runnable t) { 
     this.t = t; 
    } 
} 
+0

線程是否需要同步和寫入每個索引?如果只寫一個奇數索引而另一個只寫偶數索引則不干擾 – zapl

+0

其作業練習說明兩個線程必須寫在所有索引上。這意味着一個必須覆蓋另一個。 – Giannis

回答

0

您的解決方案有一些問題,並期待我不喜歡打印正確的結果。

一)你不等待線程完成打印生成的數組前

的情況下holder.printArray()之前添加thread1.join()thread2.join()它現在還沒有。

b)兩個線程立即通過array.writeInt(0, /* 1 or 7 */);立即開始寫入之後,他們開始相互等待。第一個索引是否正確取決於運氣。

c)在this.wait();沒有循環檢查條件後繼續是不安全的,因爲中斷可能是由另一個線程以外的其他東西引起的。我想這樣做可以,因爲這只是一個練習。

d)我看到一個潛在的死鎖:我們假設兩個線程仍在寫第一個索引。所以兩者都不在同步塊中。

線程必須通知另一個線程,寫下一個索引並進入它自己的等待塊。 但是第二個線程當時沒有在等待,所以第一個線程的notify什麼都不做。第二個線程也進入等待塊。

現在兩個線程都相互等待,什麼也沒有發生。

我沒有一個很好的簡單解決方案,因爲這個問題相當複雜。

1線程需要在索引0處開始寫入,然後等到7線程寫入索引0和1,現在1線程寫入索引1和2並等待等等。這是我看到有可能確保兩個線程都寫入到每個索引並且結果爲7-1-7-1 -....的唯一方法。同步ArrayHolder內的訪問將非常棘手,因爲它需要確保兩個線程都以正確的順序寫入每個索引。

但我認爲你的一般想法是好的。你只需要確保它是安全的

2

ThreadSeven和ThreadOne不需要是單獨的類;看起來就像複製/粘貼代碼,然後將writeInt中的7更改爲1。相反,您可以參數化該值並將其傳遞給構造函數。然後你得到這樣的東西:

public class ThreadWriter implements Runnable { 
    private final int numberToWrite; 
    // ... 
    public ThreadOne(ArrayHolder ar, Runnable t, int numberToWrite) { 
     array = ar; 
     this.t = t; 
     this.numberToWrite = numberToWrite; 
    } 
    // ... 
} 

另一點是,你的線程必須知道彼此;這不能很好地擴展。假裝爲你的下一個作業,你的老師說你必須處理三個線程,其中寫入1, 4, 7, 1, 4, 7, ...;您將不得不更改ThreadOneThreadSeven的實施。你現在可以做出的一個更好的解決方案是使ThreadWriter本身變得笨拙,並且在ArrayHolder類(或者中間類ThreadWriterManager類)中更多地管理它們的交互。