[英]Why does this thread never complete itself?
我有一个简单的Runnable类,该类应该遍历世界数据的两个维度,并在每个点执行一个功能。 我也有一个布尔值和一个返回方法,它将告诉线程何时完成。
public class Generator implements Runnable
{
private World world;
private Random seed;
private boolean genComplete = false;
public Generator(World world)
{
// Implementation
}
public boolean isComplete()
{
return genComplete;
}
/**
* Begins world generator thread.
*/
@Override
public void run()
{
world.initializeWorldTileData();
generateWholeWorld();
System.out.println("Completed");
genComplete = true;
}
/**
* Processes entire world generation tree.
*/
private void generateWholeWorld()
{
world.saveData();
for (int x = 0; x < world.getWorldSizeX(); x++)
{
for (int y = 0; y < world.getWorldSizeY(); y++)
{
// Example function.
x();
}
}
}
private void x()
{
// When nothing is performed genComplete equals true.
}
}
在此示例下,在运行时, generateWholeWorld()
方法将完全执行并打印Completed
。 但是,如果我将任何函数添加到x()
:
private void x()
{
System.out.println("Example function");
}
线程将无限运行(无限循环运行for循环),即使它应该能够在几秒钟内执行任务。 genComplete
从不等于true。
编辑:正在创建线程,并从genComplete
为true时更改的GUI加载屏幕中观察线程。
private Thread generator;
private boolean doneGenerating;
public ScreenGenerateWorld(Screen parent, InitialWorldSettings settings)
{
super(parent);
world = World.createNewWorld(settings);
this.generator = new Thread(world.getWorldGenerator());
generator.start();
}
@Override
public void update()
{
doneGenerating = world.getWorldGenerator().isComplete();
if (doneGenerating)
{
info.setText("Press \"A\" to Continue...");
if (Keyboard.isKeyDown(Keyboard.KEY_A))
AntFarm.getAntFarm().changeActiveScreen(new ScreenWorld(parent, world));
}
// Render code
}
多线程Java应用程序中的可变状态会导致数据丢失。 我强烈建议您围绕该genComplete状态变量进行一些同步,以便所有线程对其值具有共同的看法。
public class Generator implements Runnable
{
...
private boolean genComplete = false;
public synchronized void setComplete() {
getComplete = true;
}
public synchronized isComplete() {
return genComplete;
}
...
/**
* Begins world generator thread.
*/
@Override
public void run()
{
world.initializeWorldTileData();
generateWholeWorld();
System.out.println("Completed");
setComplete();
}
...
}
这只是一个假设,但似乎您获得了带有update()方法的自旋锁,该方法由JVM在几次迭代后进行了优化,以便genComplete被缓存,而自旋锁线程永远不会确定genComplete的值是否更改。 当您的方法x()为空时,方法run()快速完成,并且JVM还没有优化您的代码(默认情况下,Oracle HotSpot JIT在客户端模式下进行1500次方法调用后打开优化),但是I / O操作是1)阻塞(这意味着其他线程需要更多的CPU时间)2)速度不是很快,因此当x()包含System.out.println()时,将涉及优化。 在这种情况下,volatile将解决问题。
我最好建议您使用执行程序和回调。 例如:
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
button.setEnabled(false);
label.setText("busy");
backgroundExec.execute(new Runnable() {
public void run() {
try {
doBigComputation();
}
finally {
GuiExecutor.instance().execute(new Runnable() {
public void run() {
button.setEnabled(true);
label.setText("idle");
}
});
}
}
});
}
});
您可以从Java Concurrency in Practice中了解更多信息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.