Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jsf-2/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么这条线永远不会自己完成?_Java_Multithreading - Fatal编程技术网

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。或者将其设置为原子布尔型,或者使其易失性。易失性可能工作得更好。我一直讨厌同步,因为它让我觉得我在“发布”或暴露对象内部的东西。