我无法理解以下代码的输出。
我的理解是输出不会有任何特定的顺序,但 PlayerX started
、PlayerX
和 PlayerX dead
应该按顺序排列。而且我们应该有所有玩家应该在缓冲区日志中并且应该在最后打印。
但有时序列是 PlayerX 启动
、PlayerX 死亡
然后是 PlayerX
并且这些情况下玩家名称不在缓冲区字符串中。有人可以指出我缺少什么吗?
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();
}
}
最佳答案
首先:如果您向 Player.run()
方法添加额外的 Thread.sleep(100);
,您的代码的可能性将大大增加行为错误。
您对多线程的理解其实是正确的。
但是,您对 players[i].join();
的调用没有达到预期的效果,因为您从未启动线程 players[i]
。
相反,您将其提交给 ExecutorService
。此 ExecutorService
通过从其现有线程之一调用其 run()
方法来执行 Player
。在您的例子中,它们是执行所有玩家工作的 5 个线程。
要获得所需的结果,您有两种可能性:
不要使用
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"); }
使用
executor.awaitTermination(..)
而不是Thread.join()
:executor.shutdown(); while(!executor.isTerminated()) { try { executor.awaitTermination(1, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } }
关于java - 理解java多线程同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41025558/