2013-03-31 70 views
0

我想運行兩個線程,共享一個方法來打印出一些東西。我想要這個輸出:java中的併發循環

a b a b a b 

第一個線程打印'a'和第二個a'b'。我設法打印一次,但我不能包含一個適當的循環來交換打印。

我寫了這個代碼來執行此:

public void run() { 
    while(i<10) { 
     synchronized(this) { 
      while (turn!=turn) { 
       try { 
        turn=!turn; 
        wait(); 
        sleep(10); 
       } 
       catch(InterruptedException ie){} 
      } 

      printThreadOutput(); 
      turn=!turn; 
      i++; 
      notifyAll(); 
     } 
    } 
} 

有什麼建議?

+8

'while(turn!= turn)'? –

+0

'synchronized'應該解析非det –

+0

你的代碼包含縮進的混合標籤和空格 - 這是一個壞主意。您應該確保始終使用製表符或空格。 – thejh

回答

0
  1. 使其中一個線程在5秒之前睡覺。它將明確哪些將是線程順序。
  2. while循環不執行,因爲它的條件始終false。完全刪除內部的while,你不需要它。
  3. turn變量不是必需的。 synchronizeThread.sleep(5)將使這些線程輪流。
  4. 捕捉InterruptedException時將至少一些println
+0

「同步和Thread.sleep(5)將使這些線程輪流」。這不完全正確。當你調用Thread.sleep時,大多數JVM都會執行上下文切換,但不能保證當這個線程休眠時另一個線程會運行。如果你想保證這種行爲,你應該總是有一個控制變量。 –

+0

好!它根據你的指示工作得很好。謝謝 – b10n1k

1

一個簡單的解決方案是使用java.util.concurrent.locks.Lock,將執行所有等待和通知要求的操作:

public class ThreadTest { 

    private static final Lock lock = new ReentrantLock(); 

    public static final void main(String[] args) { 
     Runnable aRun; 
     Runnable bRun; 

     aRun = new Runnable() { 
      public void run() { 
       while (true) { 
        lock.lock(); 
        System.out.println("a"); 
        try { 
         Thread.sleep(1000); 
        } catch (InterruptedException e) { 
         Thread.currentThread().interrupt(); 
        } 
        lock.unlock(); 
       } 
      } 
     }; 

     bRun = new Runnable() { 
      public void run() { 
       while (true) { 
        lock.lock(); 
        System.out.println("b"); 
        try { 
         Thread.sleep(1000); 
        } catch (InterruptedException e) { 
         Thread.currentThread().interrupt(); 
        } 
        lock.unlock(); 
       } 
      } 
     }; 

     Thread aThread = new Thread(aRun); 
     Thread bThread = new Thread(bRun); 
     aThread.start(); 
     bThread.start(); 
    } 

} 

不使用顯示器,你可以像這樣做,但作爲@noahz虛心指出,它使用的是效率不高的Spinlock

public class ThreadTest { 

    private static volatile Boolean isATurn = true; 

    public static void main(String[] args) { 
     Runnable aRun; 
     Runnable bRun; 

     aRun = new Runnable() { 
      public void run() { 
       while (true) { 
        while (!isATurn) { 
        } 
        System.out.println("a"); 
        isATurn = false; 
       } 
      } 
     }; 

     bRun = new Runnable() { 
      public void run() { 
       while (true) { 
        while (isATurn) { 
        } 
        System.out.println("b"); 
        isATurn = true; 
       } 
      } 
     }; 

     Thread aThread = new Thread(aRun); 
     Thread bThread = new Thread(bRun); 
     aThread.start(); 
     bThread.start(); 
    } 

} 

據我所知,這保證了沒有僵局,但飢餓是可能的,如果一個線程不會終止,因爲其他的將在其上等待。但是,這不應該成爲這樣一個簡單的例子的問題。監視器也比使用輪詢更受歡迎,但是稍微涉及一些。

+0

呃。繁忙的旋轉鎖定。 – noahlz

+0

我也經歷過你的代碼,它非常有幫助。 – b10n1k

1

這是這裏上午03點半,我想睡覺了。 這是我想出了:

class TurnHolder { 

    private volatile int currentTurn; 

    public void setNextTurn() { 
    this.currentTurn = currentTurn^1; 
    } 

    public int getCurrentTurn() { 
    return currentTurn; 
    } 
} 

class Printer implements Runnable { 

    private String toPrint; 
    private TurnHolder sharedResource; 
    private int turn; 

    Printer(String toPrint, TurnHolder sharedResource, int turn) { 
    this.toPrint = toPrint; 
    this.sharedResource = sharedResource; 
    this.turn = turn; 
    } 

    @Override 
    public void run() { 

    while (true) { 
     synchronized (sharedResource) { 
     if (sharedResource.getCurrentTurn() != turn) 
      try { 
      sharedResource.wait(); 
      } catch (InterruptedException e) { 
      e.printStackTrace(); 
      } 
     System.out.println(toPrint); 
     try { 
      Thread.sleep(2000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     sharedResource.setNextTurn(); 
     sharedResource.notifyAll(); 
     } 
    } 

    } 

一種方式來運行它:

TurnHolder sharedResource = new TurnHolder(); 

Printer printerA = new Printer("a", sharedResource, 0); 
Printer printerB = new Printer("b", sharedResource, 1); 

new Thread(printerA).start(); 
new Thread(printerB).start(); 

這樣你sharedResource將保持轉彎的內存和同步上它可以讓你做什麼你必須處理這個轉彎,然後你可以轉彎。 Thread.sleep只是讓您以不錯的速度看到打印內容。 的System.out.println(toPrint);是如何提高代碼的printThreadOutput();

P.S:建議都歡迎。