2016-09-25 83 views
4

在過去的幾天裏,我一直在閱讀關於多線程的文章,並且使用多線程技術遇到了一個簡單的任務。這是任務:爲什麼此代碼中的同步功能無法正常工作?

創建一個模擬50米跑步比賽的應用程序(在我的代碼中他們是10,無所謂)。跑步者的數量應該是5,你應該給每個跑步者的線程命名。打印贏家。所有其他線程也應完成比賽。打印每位參賽選手完成比賽的時間並突出贏家的時間。

這是我寫的代碼:

public class Racer implements Runnable { 
    public static String winner; 
    public static int time = 0; 

    public void incrementTime() { 
     synchronized (Racer.class) { 
      time++; 
     } 
    } 
    public void race() { 
     for (int distance = 1; distance <= 10; distance++) { 
      incrementTime(); 
      System.out.println("Distance covered by " + Thread.currentThread().getName() + " is " + distance + " meters."); 
      boolean finalDest = this.isTheRaceOver(distance); 
      if (finalDest) { 
       break; 
      } 
     } 
    } 
    private boolean isTheRaceOver(int finalDistance) { 
     boolean isRaceOver = false; 
     if (Racer.winner == null && finalDistance == 10) { 
      String winnerName = Thread.currentThread().getName(); 
      Racer.winner = winnerName; 
      System.out.println("The winner is : " + Racer.winner + " with time " + time); 
      isRaceOver = true; 
     } else if (Racer.winner == null) { 
      isRaceOver = false; 
     } else if (finalDistance != 10) { 
      isRaceOver = false; 
     } else if (finalDistance == 10) { 
      System.out.println(Thread.currentThread().getName() + " is with time " + time); 
     } 
     return isRaceOver; 
    } 
    @Override 
    public void run() { 
     this.race(); 
    } 
} 

public class RacerDemo { 
    public static void main(String[] args) { 
     Racer racer = new Racer(); 
     Thread a = new Thread(racer, "A"); 
     Thread b = new Thread(racer, "B"); 
     Thread c = new Thread(racer, "C"); 
     Thread d = new Thread(racer, "D"); 
     Thread e = new Thread(racer, "E"); 
     a.start(); 
     b.start(); 
     c.start(); 
     d.start(); 
     e.start(); 
    } 
} 

一個輸出是:

Distance covered by A is 1 meters. 
Distance covered by C is 1 meters. 
Distance covered by C is 2 meters. 
Distance covered by C is 3 meters. 
Distance covered by C is 4 meters. 
Distance covered by C is 5 meters. 
Distance covered by C is 6 meters. 
Distance covered by C is 7 meters. 
Distance covered by C is 8 meters. 
Distance covered by C is 9 meters. 
Distance covered by C is 10 meters. 
The winner is : C with time 12 // should be 11 ? 
Distance covered by B is 1 meters. 
Distance covered by B is 2 meters. 
...... and so on 

困擾我的是,當它打印每個車手(線程)所花費的時間的事情掩蓋了距離,它並沒有顯示正確的時間。我使incrementTime()同步,但程序無法正常工作。你能告訴我什麼是錯的嗎?我的錯誤在哪裏?

回答

2

每個跑步者增加時間,導致不一致的狀態。你應該把賽車從實際的比賽中分離出來,這可能應該放在一個單獨的班級中。

您的問題發生在Racer Runnable的race方法中,其中每個跑步者增加static time字段,從而導致意想不到的行爲。

+2

這個解釋是正確的。我不知道爲什麼這是downvoted。 –

+0

是的,我知道問題來自race(),但幾分鐘前我試圖在for循環內創建一個同步塊,它似乎正常工作..我跑了幾次..但謝謝! – Roxy

0

每個跑步者都會增加時間,並且對增量時間方法只有一個鎖定。 Runner C完成他們的比賽並調用isRaceOver方法。由於c將獲得11的時間,線程b運行比賽方法,潛入並增加時間1.結果,c得到12的時間並錯誤地打印出時間。如果您的意圖是讓所有跑步者能夠增加時間,則必須確保一次只有1個線程正在競賽或IsTheRaceOver。

1

在您的實施中,time由所有線程共享。所以,如果一個線程的增量是,其他線程將讀取該值,如:

  • 線程1進入的時間race()值爲0
  • 線程1調用incrementTime()的值更改爲1個
  • 線程2進入的時間race()值爲1
  • 線程2調用incrementTime()的值更改爲2

這將使time變量處於不一致狀態。爲了避免這種情況,您可以嘗試在race()方法中使用time,以便每個線程都有自己的時間。

+0

感謝您的回答,但我有其他的想法。 – Roxy

0

由於您同步了一個默認爲原子的整數,您將得到相同的結果而沒有同步塊。同步關鍵字是不必要的,因此根本就沒有同步。

A覆蓋的距離爲1米。
C覆蓋的距離爲1米。
C覆蓋的距離爲2米。
...
獲勝者是:C與時間12 //應該是11?

從您的輸出中可以明顯看出,另一個線程也增加了時間。在打印獲勝者之前,可能會有另一個線索增加時間。要解決您的問題,您必須同步incrementTimeisTheRaceOver這兩種方法,您將確保另一個線程在打印之前不會增加時間。

但是等待:同步塊不保證更新對另一個稱爲高速緩存一致性的線程可見。如果在一個線程更新變量時不使用volatile關鍵字,則不能保證另一個線程能夠看到它。例如,即使您設置了贏家,另一個線程仍可能會將其視爲空。

確保您使用volatile關鍵字或鎖(它們也使用內存障礙)來保證更新對其他線程可見。

相關問題