Java 为什么这条线永远不会自己完成?
我有一个简单的可运行类,它应该遍历世界数据的两个维度,并在每个点执行一个函数。我还有一个布尔值和一个返回方法,它将告诉线程何时完成Java 为什么这条线永远不会自己完成?,java,multithreading,Java,Multithreading,我有一个简单的可运行类,它应该遍历世界数据的两个维度,并在每个点执行一个函数。我还有一个布尔值和一个返回方法,它将告诉线程何时完成 public class Generator implements Runnable { private World world; private Random seed; private boolean genComplete = false; public Generator(World world) { // Implementation }
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.
}
}
线程会无限地运行(无休止地在for循环中运行),即使它应该能够在几秒钟内执行任务<代码>genComplete从不等于true
编辑:正在从GUI加载屏幕创建和观察线程,当genComplete
为true时,该屏幕会发生变化
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();
}
...
}
多线程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();
}
...
}
我同意关于不变性的评论,总是倾向于使用不变性对象, 但我认为同步并不是最好的解决方案 您最好使用“执行器”而不是线程。 你可以在Jenkov博客的下一篇简短教程中阅读: 您需要向“call”函数传递一个实现,该实现实现了一个接口,该接口返回一个“Future”对象,您可以询问任务是否完成 您可以使用“get”阻塞函数来等待进程完成 我希望我正确地理解了你的需求,并且答案会对你有所帮助
祝你好运 我同意关于不变性的评论,总是倾向于使用不变性对象, 但我认为同步并不是最好的解决方案 您最好使用“执行器”而不是线程。 你可以在Jenkov博客的下一篇简短教程中阅读: 您需要向“call”函数传递一个实现,该实现实现了一个接口,该接口返回一个“Future”对象,您可以询问任务是否完成 您可以使用“get”阻塞函数来等待进程完成 我希望我正确地理解了你的需求,并且答案会对你有所帮助
祝你好运 这只是一个假设,但似乎您通过update()方法获得了一个自旋锁,JVM在多次迭代后对该方法进行了优化,以便缓存genComplete,并且自旋锁线程永远不会确定genComplete的值发生更改。当您的方法x()为空时,方法run()完成得很快,JVM还没有优化您的代码(默认情况下,Oracle HotSpot JIT在客户端模式下1500次方法调用后打开optimizatons),但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并发中了解更多信息。这只是一个假设,但似乎您通过update()方法获得了一个自旋锁,JVM在多次迭代后对其进行了优化,以便缓存genComplete,自旋锁线程永远不会确定genComplete的值已更改。当您的方法x()为空时,方法run()完成得很快,JVM还没有优化您的代码(默认情况下,Oracle HotSpot JIT在客户端模式下1500次方法调用后打开optimizatons),但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并发中学习更多内容。您需要展示更多涉及的类,包括如何生成和启动线程。您需要展示更多涉及的类,包括如何生成和启动线程。+1。或者将其设置为原子布尔型,或者使其易失性。易失性可能工作得更好。我一直讨厌同步,因为它让我觉得我在“发布”或暴露一些应该在我的对象内部的东西。+1。或者将其设置为原子布尔型,或者使其易失性。易失性可能工作得更好。我一直讨厌同步,因为它让我觉得我在“发布”或暴露对象内部的东西。