繁体   English   中英

为什么此线程永远无法完成?

[英]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();
    }
    ...
}

我同意关于不变性的评论,始终首选使用不变性对象,但我认为同步并不是最佳解决方案,

您最好使用“执行器”而不是线程。 您可以在Jenkov博客的下一个简短教程中阅读有关它的内容: Jenkov

您将需要将实现接口Callable的实现传递给“ call”函数,该接口返回一个“ Future”对象,您可以询问该对象是否已完成任务。

您可以使用“ get”阻止功能来等待进程完成。

希望我能正确地满足您的需求,并且答案会对您有所帮助。

祝好运!

这只是一个假设,但似乎您获得了带有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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM