Question

I have a Monte Carlo simulation I want to run, with a continuously updating visualisation of the current state of the system. I have a class IsingModel which provides a method Iterator<IsingModel> metropolisIterator. Calling next() on the iterator runs one cycle of the simulation, updating the state of the system. The system depends on a temperature variable IsingModel.temperature, which can be changed between iterations.

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

To visualise my simulation I have

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();
    }
}

Now what I want to do is to be able to update IsingModelTask.model with a new temperature when temperatureSlider is changed, but I believe this will cause some threading issues. What would be the best way to go about this, with a ChangeListener?

Was it helpful?

Solution

You might anyhow have a threading issue: The model is passed to the SpinPanel on the event dispatch thread. And as far as I can see, there is only one instance of the model. That means that while the Event Dispatch Thread is creating the visualization (that is, executing the code in setModel), the worker thread might already continue to modify the model.

Regarding the acutal question: You'll need a ChangeListener to react to changes in any case. The question is: What does to ChangeListener do with the new slider value? According to your description, this can not be passed to the model on the EDT, because the change might interfere with the model currently being updated on the background worker thread. A pragmatic solution could be to pass the new, updated value from the slider directly to the IsingModelTask, and pass it to the model in the doInBackground method.

OTHER TIPS

If you want one process to block the other, you could use ReadWriteLock or similar.

Or, you could use a non-blocking approach. At the start of an iteration, assign IsingModelTask.model to a local variable and reference that during processing. That way another thread can update IsingModelTask.model without affecting the current iteration halfway through. The change will be picked up at the start of the next iteration.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top