2016-12-07 2 views
0

У меня проблема с пониманием вывода следующего кода. Мое понимание вывода не будет иметь какой-либо конкретной последовательности, но PlayerX started, PlayerX и PlayerX died должны быть в последовательности. И мы должны иметь всех игроков в журнале буферов и должны быть напечатаны в конце. Но иногда последовательность PlayerX started, PlayerX died, а затем PlayerX, и в этих случаях имя игрока не в буфере. Может кто-нибудь указать, что мне не хватает?Понимание java многопоточной синхронизации

import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

public class Game { 

    public static void main(String[] args) { 
     Ball gameBall = new Ball(); 
     ExecutorService executor = Executors.newFixedThreadPool(5); 
     Player[] players = new Player[50]; 
     for (int i = 0; i < players.length; i++) { 
      Player playerTemp = new Player("Player" + i, gameBall); 
      executor.submit(playerTemp); 
      players[i] = playerTemp; 
      System.out.println(players[i].getName1() + " started"); 
     } 

     for (int i = 0; i < players.length; i++) { 

      try { 
       players[i].join(); 
       System.out.println(players[i].getName1() + " died"); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
     /* 
       * here all thread should die and following line should display 
      *all player name 
       * without any particular order 
     and should be last line. 
     */ 

     executor.shutdown(); 

     System.out.println(gameBall.getLog()); 
    } 

} 

...

class Player extends Thread { 

    private final String name; 
    private final Ball ball; 

    public Player(String aName, Ball aBall) { 
     name = aName; 
     ball = aBall; 
    } 

    @Override 
    public void run() { 
     ball.kick(name); 
    } 

    /** 
    * @return the name 
    */ 
    public String getName1() { 
     return name; 
    } 

} 

...

class Ball { 

    private volatile StringBuffer log; 

    public Ball() { 
     log = new StringBuffer(); 
    } 

    public synchronized void kick(String aPlayerName) { 

     log.append(aPlayerName + " "); 
     System.out.println(aPlayerName); 

    } 

    public String getLog() { 
     return log.toString(); 
    } 

} 
+0

Вы можете разместить некоторый вывод, который показывает, что вы говорите около? – NormR

ответ

2

Во-первых: Если добавить дополнительный Thread.sleep(100); к Player.run() -метод вы значительно увеличить вероятность того, что ваш код ведет себя неправильно.

Ваше понимание многопоточности на самом деле правильное. Однако ваш звонок в players[i].join(); не имеет эффекта, так как вы никогда не запустили нить players[i].

Вместо этого вы отправили его на номер ExecutorService. Этот ExecutorService выполняет Player, вызывая его метод run() из одного из существующих потоков. В вашем случае это 5 потоков, которые выполняют работу всех игроков.

Чтобы получить желаемые результаты у вас есть 2 возможности:

  1. Не используйте ExecutorService, но называть start() непосредственно:

    for (int i = 0; i < players.length; i++) { 
        Player playerTemp = new Player("Player" + i, gameBall); 
        playerTemp.start(); 
        players[i] = playerTemp; 
        System.out.println(players[i].getName1() +" started"); 
    } 
    
  2. Использование executor.awaitTermination(..) вместо Thread.join():

    executor.shutdown(); 
    while(!executor.isTerminated()) { 
        try { 
         executor.awaitTermination(1, TimeUnit.SECONDS); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
    } 
    
0

Я пробовал свой код, и каждый раз, когда я вижу всех игроков в журнале, просто в другом порядке. Лучше проверить журнал, если вы используете ArrayList вместо StringBuffer, тогда вы можете напечатать размер массива, который всегда возвращает 50 в моих тестах.

В вашем коде вы иногда получаете «PlayerX» и «PlayerX» в неправильном порядке, потому что «PlayerX запущен» печатается после начинается поток, в котором печатается «PlayerX». Основной поток и поток игрока выполняются одновременно, поэтому их порядок непредсказуем.

Я не понимаю, как вы можете получить «PlayerX умер» до «PlayerX», и я не вижу, что поведение в моих тестах ...

Смежные вопросы