Reputation: 3805
I have 2 buttons. 1st starts thread, 2nd makes it wait. 1st button works fine, but second doesn't want to stop 1st button thread. What's wrong? How to make it stop?
package SwingExp;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class WhichButton implements ActionListener {
JLabel jLab, testLab = new JLabel();
JFrame jfrm = new JFrame("Button example");
JButton firstButton = new JButton("First"), secondButton = new JButton("Second");
WhichButton() {
jfrm.setLayout(new FlowLayout());
jfrm.setSize(220, 90);
jfrm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
firstButton.addActionListener(this);
secondButton.addActionListener(this);
jfrm.add(firstButton);
jfrm.add(secondButton);
jLab = new JLabel("Press button");
jfrm.add(jLab);
jfrm.add(testLab);
jfrm.setVisible(true);
}
class SimpleThread extends Thread {
Thread t;
boolean suspendFlag;
SimpleThread() {
t = new Thread(this, "settingThread");
t.start();
}
public void run() {
for (int i = 0; i <= 10; i++) {
synchronized (this) {
while (suspendFlag) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}
testLab.setText(Integer.toString(i));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
firstButton.setEnabled(true);
testLab.setText("Completed.");
}
synchronized void setSuspendFlag(boolean suspendFlag) {
this.suspendFlag = suspendFlag;
}
}
public void actionPerformed(ActionEvent e) {
SimpleThread st = new SimpleThread();
if (e.getActionCommand().equals("First")) {
jLab.setText("First");
firstButton.setEnabled(false);
st.setSuspendFlag(false);
} else {
st.setSuspendFlag(true);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new WhichButton();
}
});
}
}
I was trying to use interrupt()
method, but it makes me one more thread or something like that.
Upvotes: 0
Views: 91
Reputation:
First the suspend field should be volatile
volatile boolean suspendFlag
and the second thing is you are synchronizing whole object, it means no any threads are allowed to use this object and its members, so simple synchronize on something else, like this
private Object _mutex=new Object();
public void run() {
for (int i = 0; i <= 10; i++) {
synchronized (_mutex) {
while (suspendFlag) {
try {
_mutex.wait();
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}
testLab.setText(Integer.toString(i));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
firstButton.setEnabled(true);
testLab.setText("Completed.");
}
and the suspending thread would be like this
void setSuspendFlag(boolean suspendFlag) {
this.suspendFlag = suspendFlag;
}
EDIT : also don't forget to notify about the resume the waited thread in action performed
public void actionPerformed(ActionEvent e) {
//SimpleThread st = new SimpleThread(); //what is this for?
if (e.getActionCommand().equals("First")) {
jLab.setText("First");
firstButton.setEnabled(false);
st.setSuspendFlag(false);
try{synchronized(_mutex){_mutex.notify();}}catch(Exception){}
} else {
st.setSuspendFlag(true);
}
}
Upvotes: 2
Reputation: 53674
you need to notify()
the sleeping thread in the setSuspendFlag()
method. otherwise, the thread will block forever in the wait()
call.
Also, every time your buttons are pressed, you are creating a new SimpleThread instance. you need to make the SimpleThread instance a member variable and only create it once.
Upvotes: 3