与正在运行的SwingWorker进行通信

时间:2014-02-06 15:20:40

标签: java swing swingworker

我想要运行蒙特卡罗模拟,不断更新系统当前状态的可视化。我有一个班级IsingModel,它提供了方法Iterator<IsingModel> metropolisIterator。在迭代器上调用next()运行一个模拟循环,更新系统状态。系统依赖于温度变量IsingModel.temperature,可以在迭代之间进行更改。

e.g。

int t1 = 1;
int t2 = 2;

IsingModel model = new IsingModel(t1);
Iterator<IsingModel> mItr = model.metropolisIterator();
mItr.next() // simulation undergoes one iteration with t=t1
model.setTemperature(t2);
mItr.next() // simulation undergoes one iteration with t=t2

要想象我的模拟,我有

public class IsingModelWindow extends JFrame
{
    public class SpinPanel extends JPanel
    {
        public void setModel(IsingModel model)
        {
            // some code to create a visualisation
        }

        @Override
        public void paintComponent(Graphics g)
        {
             // paint the visualisation
        }
    }

    public class TemperatureSlider extends JSlider
    {
         // some stuff
    }

    private class IsingModelTask extends SwingWorker<Void, IsingModel>
    {
        private IsingModel model;
        private Iterator<IsingModel> mItr;

        public IsingModelTask(int temp)
        {
            model = new IsingModel(temp);
            mItr = model.metropolisIterator();
        }
        @Override
        protected Void doInBackground()
        {
            while(!isCancelled())
            {
                publish(model);
                mItr.next();
            }
            return null;
        }
        @Override
        protected void process(List<IsingModel> models)
        {
            IsingModel model = models.get(models.size() - 1);
            spinPanel.setModel(model);
        }
    }

    private SpinPanel spinPanel;
    private TemperatureSlider temperatureSlider;
    private IsingModelTask task;

    public IsingModelWindow()
    {
        spinPanel = new SpinPanel();
        temperatureSlider = new TemperatureSlider();
        task = new IsingModelTask(temperatureSlider.getValue());
        task.execute();
    }
}

现在我要做的是能够在更改IsingModelTask.model时使用新的温度更新temperatureSlider,但我相信这会导致一些线程问题。使用ChangeListener

,最好的方法是什么?

2 个答案:

答案 0 :(得分:1)

您可能无论如何都有线程问题:模型传递给事件派发线程上的SpinPanel。据我所知,该模型只有一个实例。这意味着,当Event Dispatch Thread创建可视化(即,在setModel中执行代码)时,工作线程可能已经继续修改模型。

关于实际问题:在任何情况下,您都需要ChangeListener来对更改做出反应。问题是:ChangeListener对新的滑块值有什么作用?根据您的描述,这不能传递给EDT上的模型,因为更改可能会干扰当前正在后台工作线程上更新的模型。一个实用的解决方案是将新的更新值从滑块直接传递到IsingModelTask,并将其传递给doInBackground方法中的模型。

答案 1 :(得分:0)

如果您希望一个进程阻止另一个进程,可以使用ReadWriteLock或类似进程。

或者,您可以使用非阻塞方法。在迭代开始时,将IsingModelTask.model分配给局部变量并在处理期间引用它。这样,另一个线程可以在不影响当前迭代的情况下更新IsingModelTask.model。更改将在下一次迭代开始时被选中。