2017-05-07 75 views
1

我正在學習使用信號量和多線程的一般情況,但有點卡住了。我有兩個線程分別打印G和H,我的目標是交替每個線程的輸出,以便輸出字符串是這樣的;使用信號量從2個線程打印替代輸出

G 
H 
G 
H 
G 
H 

每兩個類都有類似下面

public class ClassA extends Thread implements Runnable{ 

    Semaphore semaphore = null; 
    public ClassA(Semaphore semaphore){ 

     this.semaphore = semaphore; 
    } 

    public void run() { 

     while(true) 
     { 
      try{ 
       semaphore.acquire(); 
       for(int i=0; i<1000; i++){ 
        System.out.println("F"); 

       } 
       Thread.currentThread(); 
       Thread.sleep(100); 
      }catch(Exception e) 
      { 
       System.out.println(e.toString()); 
      } 
      semaphore.release(); 
     } 

    } 

} 
下面

的一個佈局,我的主類

public static void main(String[] args) throws InterruptedException { 

    Semaphore semaphore = new Semaphore(1); 

    ClassA clasA = new ClassA(semaphore); 
    Thread t1 = new Thread(clasA); 
    ClassB clasB = new ClassB(semaphore); 
    Thread t2 = new Thread(clasB); 
    t1.start(); 
    t2.join(); 
    t2.start(); 

我得到的輸出是太不同我預期結果。任何人都可以幫助我嗎?我誤用了信號量嗎?任何幫助?

+0

如果使用固有鎖或重入鎖或信號或什麼不要緊,只是用鎖不執行任何命令 –

+0

OK,請你提出一個前進道路,以獲得預期的訂單?你會說上面代碼的弱點嗎? – Jazztheman

回答

0

信號量不能幫你解決這樣的任務。

據我所知,JVM不承諾線程執行的任何順序。這意味着如果您運行多個線程,則一個線程可以連續執行多次,並且處理器的處理時間比任何其他處理器都多。因此,如果你想讓你的線程以特定的順序執行,那麼對於最簡單的例子,你可以創建一個靜態布爾變量,它將爲你的線程起一個切換器的作用。使用wait()和notify()方法將是更好的方法,並且Interface Condition將是我想的最好的方式。

import java.io.IOException; 

public class Solution { 
    public static boolean order; 

    public static void main(String[] args) throws IOException, InterruptedException { 
     Thread t1 = new ThreadPrint("G", true); 
     Thread t2 = new ThreadPrint("O", false); 
     t1.start(); 
     t2.start(); 
     t2.join(); 

     System.out.println("Finish"); 
    } 

} 

class ThreadPrint extends Thread { 

    private String line; 
    private boolean order; 

    public ThreadPrint(String line, boolean order) { 
     this.line = line; 
     this.order = order; 
    } 

    @Override 
    public void run() { 
     int z = 0; 
     while (true) { 
      try { 
       for (int i = 0; i < 10; i++) { 
        if (order == Solution.order) { 
         System.out.print(line + " "); 
         Solution.order = !order; 
        } 
       } 
       sleep(100); 
      } catch (Exception e) { 
       System.out.println(e.toString()); 
      } 
     } 
    } 
} 

BTW可以有另一個問題原因的System.out通常是一個操作系統緩衝區和您的操作系統可以輸出在其自己的訂單郵件。

P.S.您不應該繼承Thread並同時實現Runnable

public class ClassA extends Thread implements Runnable{ 

因爲Thread類已經實現了Runnable。您只能選擇一種更適合您的目的的方式。

你應該開始一個線程然後加入到它,而不是反之亦然。

t1.start(); 
t2.join(); 
t2.start(); 
0

正如其他人所指出的那樣,鎖定本身不執行任何命令,並在此基礎之上,你無法確定當一個線程開始(調用Thread.start()將在未來的某個時刻開始線程,但是這可能需要一段時間)。

但是,您可以使用鎖定(如Semaphore)來執行訂單。在這種情況下,可以使用兩個信號量來打開和關閉線程(備用)。這兩個線程(或Runnables)確實需要提前知道對方 - 線程可以「加入」派對的更加動態的方法將更加複雜。

在具有可重複結果的可運行示例類下面(測試多線程時總是一件好事)。我會讓你知道爲什麼以及它是如何工作的。

import java.util.concurrent.*; 

public class AlternateSem implements Runnable { 

    static final CountDownLatch DONE_LATCH = new CountDownLatch(2); 
    static final int TIMEOUT_MS = 1000; 
    static final int MAX_LOOPS = 10; 

    public static void main(String[] args) { 

     ExecutorService executor = Executors.newCachedThreadPool(); 
     try { 
      AlternateSem as1 = new AlternateSem(false); 
      AlternateSem as2 = new AlternateSem(true); 
      as1.setAlternate(as2); 
      as2.setAlternate(as1); 
      executor.execute(as1); 
      executor.execute(as2); 
      if (DONE_LATCH.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 
       System.out.println(); 
       System.out.println("Done"); 
      } else { 
       System.out.println("Timeout"); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } finally { 
      executor.shutdownNow(); 
     } 
    } 

    final Semaphore sem = new Semaphore(0); 
    final boolean odd; 
    AlternateSem other; 

    public AlternateSem(boolean odd) { 
     this.odd = odd; 
    } 

    void setAlternate(AlternateSem other) { this.other = other; } 
    void release() { sem.release(); } 
    void acquire() throws Exception { sem.acquire(); } 

    @Override 
    public void run() { 

     if (odd) { 
      other.release(); 
     } 
     int i = 0; 
     try { 
      while (i < MAX_LOOPS) { 
       i++; 
       other.acquire(); 
       System.out.print(odd ? "G " : "H "); 
       release(); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     DONE_LATCH.countDown(); 
    } 
}