我想要运行蒙特卡罗模拟,不断更新系统当前状态的可视化。我有一个班级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
?
答案 0 :(得分:1)
您可能无论如何都有线程问题:模型传递给事件派发线程上的SpinPanel
。据我所知,该模型只有一个实例。这意味着,当Event Dispatch Thread创建可视化(即,在setModel
中执行代码)时,工作线程可能已经继续修改模型。
关于实际问题:在任何情况下,您都需要ChangeListener
来对更改做出反应。问题是:ChangeListener对新的滑块值有什么作用?根据您的描述,这不能传递给EDT上的模型,因为更改可能会干扰当前正在后台工作线程上更新的模型。一个实用的解决方案是将新的更新值从滑块直接传递到IsingModelTask
,并将其传递给doInBackground
方法中的模型。
答案 1 :(得分:0)
如果您希望一个进程阻止另一个进程,可以使用ReadWriteLock或类似进程。
或者,您可以使用非阻塞方法。在迭代开始时,将IsingModelTask.model
分配给局部变量并在处理期间引用它。这样,另一个线程可以在不影响当前迭代的情况下更新IsingModelTask.model
。更改将在下一次迭代开始时被选中。