Reputation: 716
I have gone through pretty much every question on java multithreading here on SO, but I do not quite understand if my understanding is correct.
I wish to understand if the sequence of operations plays out as I have described below.
import javax.swing.*;
import java.awt.FlowLayout;
import java.awt.event.*;
class Runner implements Runnable{
long count = 0;
JLabel label;
boolean paused = false;
public Runner(JLabel label){
this.label = label;
}
public void run(){
while(true){
try {
if(paused){
synchronized(this){
wait();
}
}
} catch(InterruptedException e) {}
count++;
label.setText(Long.toString(count));
if(Thread.interrupted())
return;
}
}
synchronized void pause_counting(){
paused = true;
}
synchronized void start_counting(){
paused = false;
notifyAll();
}
}
public class ThreadRace extends JApplet{
boolean running = true;
Thread thread;
@Override
public void init(){
final JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
JLabel threadProgress = new JLabel("0");
final Runner runner = new Runner(threadProgress);
thread = new Thread(runner);
thread.start();
panel.add(threadProgress);
JButton toggle = new JButton("Stop");
toggle.addActionListener(new ActionListener() {
@Override
synchronized public void actionPerformed(ActionEvent e) {
System.out.println("Running: " + running);
if(running){
runner.pause_counting();
} else {
runner.start_counting();
}
running = !running;
}
});
panel.add(toggle);
add(panel);
}
public void stop(){
thread.interrupt();
}
}
Is this how it works?
pause_counting()
, I am setting paused to false.runner
inside of the synchronized(this) { ... }
block.this.wait()
, I am releasing hold of the same lock which I just took possession of and go into the WAITING
state.runner
(!)start_counting()
eventually.RUNNING
state and continues from after the wait() statement. While it is still inside the synchronized(this)
block, it gets hold of the lockI am pretty sure there are a few flaws in my understanding.
Help? :(
Upvotes: 2
Views: 132
Reputation: 116938
Is this how it works?
Yes. All of your statements are true with some tweaks (see below).
However, there is are bugs in your program. Because the thread is testing for paused
while not inside of a synchronized
block, you need to make sure that paused
is volatile
to provide memory synchronization.
volatile boolean paused = false
This is probably also necessary with the JLabel
array as well. Any time you have a threads that are changing shared variables, there needs to be memory synchronization.
When I call the method pause_counting(), I am setting paused to false.
Yes. Updating paused
here is ok because it is in a synchronized
method.
Inside of run(), I am taking hold of the lock to an object, runner[i] inside of the synchronized(this) { ... } block.
Only if paused
is true. Since you are testing for paused
outside of the synchronized
block, paused
needs to be volatile
to ensure memory synchronization between threads.
When I make a call to this.wait(), I am releasing hold of the same lock which I just took possession of and go into the WAITING state.
Right.
At this point, any other method is free to do anything with this runner[i] (!)
Well it was free to do stuff before but now that the lock is released it can call synchronized
methods without blocking.
I make a call to start_counting() eventually.
Right. This calls notifyAll()
.
This makes the thread go back into the RUNNING state and continues from after the wait() statement. While it is still inside the synchronized(this) block, it gets hold of the lock
Well first it makes the thread go into the BLOCKED
state until the caller of start_counting()
leaves that method and releases the lock.
However, once it leaves the block, it releases the lock and execution continues
Right.
Upvotes: 2