First of all, I know there are several topics regarding my problem and I've read many... The best I found is from Java Docu ( link ) and I tried to adapt their solution.
But unfortunately my little game of life program isn't working as expected... When I pause the Thread who simulates the game (painting next generation to JPanel) it stops as expected, when I then try to resume, nothing happens (no exception, no chance to debug). What I of course can do is, stop the thread completly and create a new one which acts then as pause/resume... I don't want to use that work-around, because I want to understand the problem I've created and secondly I want to use the start thread differently ;)
So here's the code which produces the thread (I mainly worked with volatile and synchronized):
public class MainJFrame extends JFrame {
private static final long serialVersionUID = 1L;
private JPanelGrid jPanelGrid;
private volatile Thread simulation;
private volatile boolean threadSuspended;
private JMenuBar menuBar;
private JMenu main;
public MainJFrame() {
jPanelGrid = new JPanelGrid(995, 770);
getContentPane().add(jPanelGrid);
initMenuBar();
setJMenuBar(menuBar);
pack();
setTitle("Conrads Game of Life");
setSize(1000, 800);
setLocationRelativeTo(null); // displayed in the middle of the screen
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public void startSimulation() {
//jPanelGrid.reset();
threadSuspended = false;
simulation = new Thread() {
@Override
public void run() {
Thread thisThread = Thread.currentThread();
while (simulation == thisThread) { //this check is for the correct stop of the thread
try {
Thread.sleep(50);
if(threadSuspended){ //this additional if is a performance tweak regarding Java Docu
synchronized (this) { //this part should be for the pause and resume feature
while (threadSuspended) {
wait();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
jPanelGrid.paintNextGen(); //Do I access it incorrectly?
}
}
};
simulation.start();
}
public synchronized void stopSimulation() {
simulation = null;
notifyAll();
}
public synchronized void pauseResume(){
threadSuspended = !threadSuspended;
if(!threadSuspended){
notifyAll();
}
}
private void initMenuBar(){
menuBar = new JMenuBar();
main = new JMenu("Main");
menuBar.add(main);
JMenuItem pauseResume = new JMenuItem("Pause/Resume");
pauseResume.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
pauseResume();
}
});
main.add(pauseResume);
JMenuItem start = new JMenuItem("Start");
start.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
startSimulation();
}
});
main.add(start);
JMenuItem stop = new JMenuItem("Stop");
stop.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
stopSimulation();
}
});
main.add(stop);
}
}
Main problem
You are sharing the threadSuspended
variable across different threads. You are protecting it by synchronized
, but you are synchronizing on different objects.
synchronized (this)
<-- here this
is a Thread
object, try using JFrame.this
instead
public synchronized void pauseResume(){
<-- here you are synchronizing on a JFrame
object
EDIT : Deleted section about double-checking, you are using volatile
so post Java 5.0 this code should be ok I think. See https://en.wikipedia.org/wiki/Double-checked_locking for more information.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.