我无法理解以下代码的输出。
我的理解是输出没有任何特定的顺序,但PlayerX started
,PlayerX
和PlayerX died
应该按顺序排列。我们应该让所有玩家都在缓冲区日志中并且应该打印到最后。
但有时候序列是PlayerX started
,PlayerX died
然后是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();
}
}
答案 0 :(得分:2)
首先关闭:如果您向Thread.sleep(100);
方法添加额外的Player.run()
,则会大大增加代码行为错误的可能性。
您对多线程的理解实际上是正确的。
但是,由于您从未启动线程players[i].join();
,因此您对players[i]
的调用没有达到预期的效果。
而是将其提交给ExecutorService
。此ExecutorService
通过从其现有线程之一调用其Player
- 方法来执行run()
。在你的情况下,他们是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();
}
}
答案 1 :(得分:0)
我已经尝试过你的代码了,每当我看到日志中的所有玩家时,只是按照不同的顺序。如果使用ArrayList
而不是StringBuffer
,则检查日志会更容易,然后您可以打印数组的大小,在我的测试中总是返回50。
在你的代码中你会得到&#34; PlayerX&#34;和#34; PlayerX开始&#34;有时候错误的顺序,因为&#34; PlayerX开始&#34; 在线程开始后打印&#34; PlayerX&#34;打印出来。主线程和播放器线程同时运行,因此它们的顺序是不可预测的。
我不知道你怎么能得到&#34; PlayerX死了#34;之前&#34; PlayerX&#34;,我在测试中没有看到这种行为...