I'm currently building a Java application using two threads :
The first thread is about the UI of the application, and also the processing of command received via the bluetooth thread.
The bluetooth thread is bluetooth server waiting for a robot to connect and handling communication.
As of now, the UI thread is in wait() state until the bluetooth thread gets a new message to process.
The problem is, I can trace the notify/notifyAll call from the bluetooth thread, but my UI is not resuming it's activity.
I am now sure I misunderstood something about the proper way to manage synchronized threads, but I can't figure out what's wrong in my software.
Here is the code for the UI :
package mapper;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
public class MapperUI extends JFrame implements Runnable {
private ArrayList<String> messageArray;
public MapperUI(){
super();
build();
this.setVisible(true);
new Thread(this).start();
}
private void build(){
setTitle("SLAM Mapper");
setSize(600,500);
setLocationRelativeTo(null);
setResizable(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setContentPane(buildContentPane());
}
private JPanel buildContentPane(){
JPanel main = new JPanel();
main.setLayout(new BorderLayout());
//TODO Implements auto-generated map after bluetooth communication
MapPanel map = new MapPanel();
main.add(map,BorderLayout.CENTER);
//TODO This fields will be buildt with stored message
JTable positions = new JTable(15,2);
main.add(positions,BorderLayout.EAST);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout());
JButton bouton = new JButton("Start");
buttonPanel.add(bouton);
JButton bouton2 = new JButton("Send");
buttonPanel.add(bouton2);
main.add(buttonPanel,BorderLayout.SOUTH);
return main;
}
public synchronized void run(){
MapperCom bt = new MapperCom();
while(true){
try {
System.out.println("Mapper is Waiting......");
wait();
String message = bt.getMessage();
this.messageArray.add(message);
bt.setNextCommand(processMessage(message));
notifyAll();
System.out.println("Mapper Notify");
build();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public String processMessage(String message){
String command = "";
//TODO Build a response
command = "fffff\n";
return command;
}
}
Here is the bluetoothService :
package mapper;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.UUID;
import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;
import javax.microedition.io.StreamConnectionNotifier;
public class MapperCom extends Thread {
public final UUID uuid = new UUID(
"27012f0c68af4fbf8dbe6bbaf7aa432a", false);
public final String name = "Server";
public final String url = "btspp://localhost:" + uuid
+ ";name=" + name
+ ";authenticate=false;encrypt=false;";
private LocalDevice local ;
private StreamConnectionNotifier server ;
private StreamConnection conn ;
private DataInputStream din ;
private DataOutputStream dout ;
private String command;
private String message;
public MapperCom(){
try {
this.command = "";
this.message = "";
System.out.println("Setting device to be discoverable...");
local = LocalDevice.getLocalDevice();
local.setDiscoverable(DiscoveryAgent.GIAC);
System.out.println("Start advertising service...");
server = (StreamConnectionNotifier)Connector.open(url);
System.out.println("Waiting for incoming connection...\n");
conn = server.acceptAndOpen();
System.out.println("Client Connected...");
din = new DataInputStream(conn.openInputStream());
dout = new DataOutputStream(conn.openOutputStream());
new Thread(this).start();
} catch (Exception e) {
System.out.println("Exception Occured: " + e.toString());
}
}
#Override
public synchronized void run(){
System.out.println("Bluetooth Thread Started");
while(true){
try {
String cmd = "";
char c;
System.out.println("Waiting for message");
while (((c = din.readChar()) > 0) && (c!='\n') ){
System.out.println("Char received :"+c);
cmd = cmd + c;
}
storeMessage(cmd);
System.out.println("Bt Notify......");
notifyAll();
System.out.println("Bt is Waiting for a command from mapper......");
wait();
sendResponse();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void sendResponse(){
try {
dout.writeChars(command);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public synchronized String getMessage(){
return this.message;
}
public synchronized void storeMessage (String data){
this.message = data;
System.out.println("Received " + data);
}
public synchronized int setNextCommand (String data){
int result = -1;
//TODO Implement proper protocol
this.command = data;
System.out.println("Sending " + data);
return result;
}
}
I think when you call notifyAll(), it calls this.notifyAll(). Which there are no other elements waiting in the same class. So what you can do is you share the same object over both classes and call obj.wait() and obj.notifyAll(). It will work.
Below is one sample program. Basically there needs some common lock between 2 threads if you want communication using wait & notify.
package ravi.tutorial.java.threads;
public class TestThreads {
/**
* #param args
*/
public static void main(String[] args) {
CommonLock commonLock = new CommonLock();
Thread1 thread1 = new Thread1(commonLock);
Thread2 thread2 = new Thread2(commonLock);
thread1.start();
thread2.start();
}
}
/*
* Common monitor lock between both threads, used for communication using wait
* notify.
*/
class CommonLock {
}
// Extending Thread instead of Runnable as its just a test
class Thread1 extends Thread {
private CommonLock commonLock;
public Thread1(CommonLock commonLock) {
this.commonLock = commonLock;
}
public void run() {
System.out.println("Started thread 1");
System.out.println("waiting thread 1");
try {
// TO wait on commonLock, first need to get lock on commonLock. SO
// put synchronized block of commonLock.
synchronized (commonLock) {
commonLock.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("DONE waiting thread 1 as I got notification from THread 2");
}
}
class Thread2 extends Thread {
private CommonLock commonLock;
public Thread2(CommonLock commonLock) {
this.commonLock = commonLock;
}
public void run() {
System.out.println("Running thread 2");
try {
System.out.println("Sleeping thread 2");
// Just take gap of 2 sec before notifying.
Thread.sleep(2000);
// TO notify on commonLock, first need to get lock on commonLock. SO
// put synchronized block of commonLock.
synchronized (commonLock) {
System.out.println("Notifying thread 2");
commonLock.notifyAll();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Look at this: Thread tutorial
wait( ) tells the calling thread to give up the monitor and go to
sleep until some other thread enters the same monitor and calls
notify( ).
notify( ) wakes up the first thread that called wait( ) on
the same object.
notifyAll( ) wakes up all the threads that called wait( ) on the
same object. The highest priority thread will run first.
This is main misunderstanding of thread conception in Java.
Related
I am implementing a Chatting program. Whenever the user clicks "START" in Player.java, it will terminates the previous Chatter thread and build a new thread to start. The Chatter thread has GUI for chatting.
I terminate the Chatter thread by the interrupt() method. I thought it will set the flag in Chatter thread so that it will be terminated by checking isInterrupted() but it is always false. But it is supposed to be true when I call interrupt() in Player.java
Here is my code:
Player.java
public class Player implements GameConstants{
/**
* This listener is used when the user clicks QUIT in the GUI.
*/
private class ControlListener implements ActionListener{
/**
* This method sends QUIT to the server when the listener is triggered.
* #param e ActionEvent
*/
#Override
public void actionPerformed(ActionEvent e){
String cmd = ((JButton)(e.getSource())).getText();
if ("START".equals(cmd)) {
//I interrupt the thread using this
if (chatThread !=null) {
System.err.println("before interruped");
chatThread.interrupt();
}
chatThread = new Chatter(ip,senderName);
chatThread.start();
}
}
}
}
Here is Chatter.java
public class Chatter extends Thread implements GameConstants{
private JTextArea log;
private String senderName;
private DataInputStream fromServer;
private DataOutputStream toServer;
private JTextField inputField;
private SoundPlayer msgSound;
private Socket socket;
private class SendListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent e){
String msg = inputField.getText();
inputField.setText("");
try {
toServer.writeUTF(""+(new Date())+ "\n" + senderName + ": "+msg);
toServer.flush();
} catch(IOException ex) {
System.err.println(ex.getMessage());
}
}
}
public Chatter(String ip, String senderName){
this.senderName = senderName;
buildGUI();
try{
socket = new Socket(ip,CHAT_PORT);
fromServer = new DataInputStream(socket.getInputStream());
toServer = new DataOutputStream(socket.getOutputStream());
}catch(IOException e){
System.out.println(e.getMessage());
}
}
#Override
public void run(){
try {
while(!isInterrupted()){
String msg = fromServer.readUTF();
report(msg);
}
} catch(IOException e) {
System.err.println(e.getMessage());
}finally{
try {
socket.close();
} catch(Exception e) {
}
}
}
private void buildGUI(){
JFrame frame = new JFrame();
frame.setSize(WIDTH,HEIGHT);
frame.setTitle("Chat Room - " + senderName);
frame.setResizable(false);
// .... just building the GUI
frame.add(parentPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
When you interrupt a Thread, it may throw InterruptedException if it's waiting for some IO operations or like that. Its Interrupted flag will be cleared after Exception is thrown and will be false again.
I read a lot about Java Threads but I am not sure about the optimal solution.
I create a worker thread to access a php-Script (and the php-Script accesses a mysql-database). If somehow the server with the php-Script or the mysql-database is busy the Thread freazes in a read or send operation. Therefore the concept of setting an interupt and have the Thread stop itself does not work.
Now I created a second worker thread with a ProgressMonitor. When the user clicks the cancel button of the ProgressMonitor the frozen first Thread is canceled.
In case the first Thread works okay, it cancels the second Thread. Therefore the two Threads can cancel each other.
But is this the optimal solution? Is there a better and safer way to do this?
class ArbeiterErstelleTabellenmodell extends SwingWorker<TabellenmodellMitarbeiter, Object>
{
ProgressMonitor anzeige;
ErstelleTabellenmodellMitAnzeige fadenAnzeige;
ArbeiterErstelleTabellenmodell(ProgressMonitor anzeige, ErstelleTabellenmodellMitAnzeige fadenAnzeige)
{
this.anzeige = anzeige;
this.fadenAnzeige = fadenAnzeige;
}
#Override
public TabellenmodellMitarbeiter doInBackground()
{
this.anzeige.setProgress(0);
this.anzeige.setNote("1.) Datenabfrage aufrufen ...");
TabellenmodellMitarbeiter tm = new TabellenmodellMitarbeiter();
String daten = null;
try
{
URL url = new URL("http://www.greif-integra.de/daten/php/mitarbeiter/select_mitarbeiter_tabelle.php");
PhpPostConnect con = new PhpPostConnect(url);
this.anzeige.setProgress(30);
this.anzeige.setNote("2.) Daten lesen ...");
try
{
daten = con.read();
this.anzeige.setProgress(60);
this.anzeige.setNote("3.) Daten aufbereiten ...");
// here the received data is being processed
}
catch (IOException e)
{
meldungTabelle.setText("FEHLER Die Tabelle kann nicht angezeigt werden. IOException");
}
}
catch (MalformedURLException e)
{
meldungTabelle.setText("FEHLER Die Tabelle kann nicht angezeigt werden. MalformedURLException");
}
catch (Exception e)
{
meldungTabelle.setText("FEHLER Die Tabelle kann nicht angezeigt werden. Exception");
}
this.anzeige.setProgress(90);
this.anzeige.setNote("4.) Die Tabelle erzeugen ...");
return tm;
}
#Override protected void done()
{
// some work with the data is done here
this.fadenAnzeige.cancel(true);
this.anzeige.close();
}
}
In my Java program I start and execute an object of this second class.
class ErstelleTabellenmodellMitAnzeige extends SwingWorker<Object, Object>
{
#Override
protected Object doInBackground()
{
ProgressMonitor anzeige = new ProgressMonitor(KarteMitarbeiter.this,
"Fortschrittsanzeige",
"",
0,
100);
ArbeiterErstelleTabellenmodell fadenTabellenmodell = new ArbeiterErstelleTabellenmodell(anzeige, this);
fadenTabellenmodell.execute();
while(true)
{
try
{
Thread.sleep(500);
}
catch (InterruptedException e)
{}
if(anzeige.isCanceled())
{
fadenTabellenmodell.cancel(true);
break;
}
}
anzeige.close();
return null;
}
}
Maybe there is no optimal solution. I just want to make sure because I want to use the software every day. Thank you in advance. I appreciate your ideas.
Therefore the two Threads can cancel each other. But is this the optimal solution? Is there a better and safer way to do this?
The best solution is to set a volatile flag which is being checked regularly to see if the thread should stop running. If you are blocking on a Stream, you can close the stream and cause it to trigger an IOException (like AsynchronousCloseException for Channels)
If you really have no choice, you can use thread.stop(); This will cause the thread to throw a ThreadDeath Error which should trigger it to unwind the stack (and any locks) and cause your thread to die. This should only be used as a last resource and it could leave data in an inconsistent state. i.e. the error could be thrown on any line.
Note: If you catch Throwable, or Error or ThreadDeath, this will catch this error, just like any other and the thread won't die.
You can get rid of one thread as long you as you are notified that the user clicked "Cancel". I made a working example using code from the answers here and here.
You will need to download the SwingUtils class to make the example work.
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.atomic.AtomicReference;
import javax.accessibility.AccessibleContext;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.ProgressMonitor;
import javax.swing.SwingUtilities;
public class Q22126862 {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new SwingWorkerExample();
}
});
}
static class SwingWorkerExample extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
private final JButton startButton;
private MySwingWorker swingWorker;
public SwingWorkerExample() {
super("SwingWorkerExample");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new GridLayout(2, 2));
startButton = makeButton("Start");
//Display the window.
pack();
setVisible(true);
}
private JButton makeButton(String caption) {
JButton b = new JButton(caption);
b.setActionCommand(caption);
b.addActionListener(this);
getContentPane().add(b);
return b;
}
#Override
public void actionPerformed(ActionEvent e) {
if ("Start".equals(e.getActionCommand())) {
startButton.setEnabled(false);
// Note that it creates a new instance of the SwingWorker-derived class. Never reuse an old one.
ProgressMonitor progressMonitor = new ProgressMonitor(this, "Sleep progress", "sleeping", 0, 99);
(swingWorker = new MySwingWorker(this, progressMonitor, 3000, 10)).execute(); // new instance
} else if ("TaskDone".equals(e.getActionCommand())) {
startButton.setEnabled(true);
System.out.println("SwingWorker task finished OK: " + swingWorker.getResult());
} else {
System.out.println("Unknown action: " + e);
}
}
}
static class MySwingWorker extends javax.swing.SwingWorker<Boolean, Void> implements ActionListener {
private final ActionListener taskListener;
private final long sleepMs;
private final int sleepSteps;
private final ProgressMonitor progressMonitor;
private final AtomicReference<Thread> currentThread = new AtomicReference<Thread>();
private volatile boolean done;
private JButton cancelButton;
private boolean result;
public MySwingWorker(ActionListener taskListener, ProgressMonitor progressMonitor, long sleepMs, int sleepSteps) {
super();
this.taskListener = taskListener;
this.sleepMs = sleepMs;
this.sleepSteps = sleepSteps;
this.progressMonitor = progressMonitor;
}
#Override
protected Boolean doInBackground() {
currentThread.set(Thread.currentThread());
long sleepTimeMs = sleepMs / sleepSteps;
try {
// Initialize the progress monitor so that it has a backing JDialog
progressMonitor.setMillisToDecideToPopup(0);
progressMonitor.setProgress(0);
AccessibleContext ac = progressMonitor.getAccessibleContext();
JDialog dialog = (JDialog)ac.getAccessibleParent();
java.util.List<JButton> components = darrylbu.util.SwingUtils.getDescendantsOfType(JButton.class, dialog, true);
cancelButton = components.get(0);
cancelButton.addActionListener(this);
for (int i = 0; i < sleepSteps; i++) {
Thread.sleep(sleepTimeMs);
int progress = (int)((i / ((float)sleepSteps)) * 100.0);
progressMonitor.setProgress(progress);
System.out.println("Sleep progress: " + progress);
}
result = true;
} catch (Exception e) {
//e.printStackTrace();
System.out.println(e.toString());
} finally {
done = true;
currentThread.set(null);
System.out.println("Background task done");
}
return result;
}
public Boolean getResult() {
return result;
}
#Override
protected void done() {
System.out.println("Task done");
progressMonitor.close();
System.out.println("Monitor closed");
ActionEvent e = new ActionEvent(this, 0, "TaskDone");
taskListener.actionPerformed(e);
}
protected void cancel() {
if (done) {
return;
}
Thread t = currentThread.get();
if (t != null) {
t.interrupt();
}
// In case if I/O-tasks, close the source that is read from (e.g. socket).
// Interrupting a blocked reading thread has no effect in this case.
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Action: " + e);
if ("Cancel".equals(e.getActionCommand())) {
cancel();
}
}
}
}
Marko Topolnik got me on the right track:
I don't see any improvement from having two worker threads. Your
fundamental issue is the usage of non-interruptible blocking I/O
operations. – Marko Topolnik
The blocking I/O had to be changed.
I am using URLConnection and now I discovered that it is possible to do
.setConnectTimeout(1500);
.setReadTimeout(1800);
Now I do not need to stop the WorkerThread because the IO Operation will throw an exception on the WorkerThread when it is stuck.
Anyway before I found this easy solution I did the trick by using a get() with a timeout-parameter to retrieve the result from the WorkerThread. This throws a TimeoutException which can be used to do cancel() on the WorkerThread. The WorkerThread has to check on if(canceled())return; to stop itself.
I have looked everywhere. How to suspend/pause it by code until I call it to awake using any java.util.concurrentmethods/objects? I have simple Thread with run method:
When I press button it stops then starts but the problem is that I get exception when I start it again. I want it play/pause like in the media player.
Exception in thread "AWT-EventQueue-0" java.lang.IllegalMonitorStateException
Full working code(with exceptions):
import java.awt.GridLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
public class Window extends JFrame {
ThreadPanel leftPanel, rightPanel;
Thread leftThread, rightThread;
public Window() {
super("StopResume");
}
public void createGUI() {
setLayout(new GridLayout());
add(leftPanel = new ThreadPanel());
add(rightPanel = new ThreadPanel());
leftThread = new Thread(leftPanel);
rightThread = new Thread(rightPanel);
leftThread.start();
rightThread.start();
setSize(800, 600);
setVisible(true);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
int confirmed = JOptionPane.showConfirmDialog(null, "Zamknąć", "Potwierdzenie", JOptionPane.OK_CANCEL_OPTION);
if (confirmed == JOptionPane.OK_OPTION) {
dispose();//tu podmienic kod
System.exit(1);
}
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Window().createGUI();
}
});
}
}
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class ThreadPanel extends JPanel implements Runnable {
public static final String SUSPENDED = "GO", RUNNING = "SUSPEND";
JTextArea txt;
JButton ppButton;
DateFormat dateFormat;
Lock lock;
Condition cond;
boolean running;
public ThreadPanel() {
super();
createGUI();
dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
lock = new ReentrantLock();
cond = lock.newCondition();
running = true;
}
public void createGUI() {
setLayout(new BorderLayout());
JScrollPane jsp = new JScrollPane(txt = new JTextArea(), JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
add(jsp, BorderLayout.CENTER);
add(ppButton = new JButton(RUNNING), BorderLayout.SOUTH);
ppButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println(1);
if (running) {
running = false;
ppButton.setText(SUSPENDED);
} else {
running = true;
ppButton.setText(RUNNING);
lock.unlock();
}
lock.lock();
if (!running) {
cond.signalAll();
}
lock.unlock();
}
});
}
#Override
public void run() {
while (true) {
lock.lock();
try {
if (!running)
cond.await();
} catch (Exception e) {
e.printStackTrace();
}
Calendar cal = Calendar.getInstance();
txt.append("\n" + dateFormat.format(cal.getTime()));
try {
Thread.sleep((long) (Math.random() * 1001 + 500));
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(2);
lock.unlock();
}
}
}
I see you want a button to start and stop the thread. So basically you need to in the actionPerformed(), acquire the lock, look up the state of things, manipulate the state, tell the waiting entity that something changed, and then release all your locks.
The Runnable thread (for lack of a label) should remain mostly unchanged but should check the Condition within a loop to avoid the case where your signalAll() wakes and the Condition still is not symenticly true or false. (signal() and signalAll() are not guaranteed to be sync right after the lock is released, so 2 calls to actionPerformed() may have happened already).
public void createGUI() {
setLayout(new BorderLayout());
JScrollPane jsp = new JScrollPane(txt = new JTextArea(), JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
add(jsp, BorderLayout.CENTER);
add(ppButton = new JButton(RUNNING), BorderLayout.SOUTH);
ppButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
// This is where we acquire the lock to safely look at the state
lock.lock();
System.out.println(1);
// Manipulate the state
if (running) {
running = false;
ppButton.setText(SUSPENDED);
} else {
running = true;
ppButton.setText(RUNNING);
}
// Signal that this conditional changed (is either true or false now)
cond.signalAll();
// Release the lock so other entities can go forward
lock.unlock();
}
});
}
#Override
public void run() {
while (true) {
lock.lock();
try {
// This should block until this condition is true with a loop
while (!running)
cond.await();
} catch (Exception e) {
e.printStackTrace();
}
Calendar cal = Calendar.getInstance();
txt.append("\n" + dateFormat.format(cal.getTime()));
// No need to sleep()
System.out.println(2);
lock.unlock();
}
}
}
One way to do what I think you're asking for is to use a CyclicBarrier (from java.util.concurrent), parameterising it with two "parties".
The first thread to call await on the barrier will be suspended/blocked until a second thread also calls await, at which point both threads can proceed.
Here's a simple code sample:
import java.util.concurrent.CyclicBarrier;
public class Test {
public static void main(String[] args) {
// a barrier requiring two threads to call await before
// any thread can proceed past the barrier
final CyclicBarrier barrier = new CyclicBarrier(2);
new Thread(){
#Override
public void run() {
try {
// do some stuff
System.out.println("in thread, before the barrier");
// calling await blocks until two threads
// (this one and one other) have called await
barrier.await();
// do some more stuff
System.out.println("in thread, after the barrier");
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
try {
System.out.println("main thread, before barrier");
// calling await blocks until two threads
// (this one and one other) have called await
barrier.await();
System.out.println("main thread, after barrier");
} catch (Exception exc) {
exc.printStackTrace();
}
}
}
I have already seen this question : How pause and then resume a thread?
I have seen many questions in stackoverflow related to my issue, but I couldn't understand them because they are abstract and not specific enough to my sitiuation.
There are 2 Count Down Labels. When you click Start Button, the countdown is executed. In the same way, when you click Pause Button, it should be paused. However, I am getting an error: Exception in thread "AWT-EventQueue-0" java.lang.IllegalMonitorStateException
2 Threads are started, but I can't stop it with the wait() method. Please let me know how can I stop threads, and implement resume button. Thanks. Easy Example below
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
class FirstCountDown extends SwingWorker<Integer, Integer> {
public Integer doInBackground() {
for(int i=0; i<1000; i++){
CountDown.count1.setText(String.valueOf(1000-i));
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
}
class SecondCountDown extends SwingWorker<Integer, Integer> {
public Integer doInBackground(){
for(int i=0; i<1000; i++){
CountDown.count2.setText(String.valueOf(1000-i));
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
}
class CountDown extends JFrame {
static JLabel count1;
static JLabel count2;
static JButton startButton;
static JButton pauseButton;
static JButton resumeButton;
FirstCountDown first = new FirstCountDown();
SecondCountDown second = new SecondCountDown();
public CountDown(){
count1 = new JLabel("1000");
count2 = new JLabel("1000");
startButton = new JButton("start");
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
first.execute();
second.execute();
}
});
pauseButton = new JButton("pause");
pauseButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
try {
first.wait();
second.wait();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
resumeButton = new JButton("resume");
setSize(300,100);
setLayout(new FlowLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(count1);
add(count2);
add(startButton);
add(pauseButton);
add(resumeButton);
setVisible(true);
}
public static void main(String args[]) {
CountDown g = new CountDown();
}
}
You can't suspend a thread execution by invoking wait() on it. wait() suspend the current thread until another thread calls notify() or notifyAll() on the same object the previous thread called wait() on. Moreover, in order to call wait(), notify() or notifyAll() on an object, the calling thread must hold that object's monitor by doing
synchronized(object) {
object.wait();
}
In order to suspend your counting, you need a flag and provide two methods to suspend and resume your counting. Something like:
class FirstCountDown extends SwingWorker<Integer, Integer> {
private _suspended = false;
public synchronized void suspend() { _suspended = true; notify(); }
public synchronized void resume() { _suspended = false; notify(); }
public Integer doInBackground() {
for(int i=0; i<1000; i++) {
synchronized(this) {
while (_suspended) {
wait(); // The current thread will block until some else calls notify()
// Then if _suspended is false, it keeps looping the for
}
}
CountDown.count1.setText(String.valueOf(1000-i));
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
}
This question already has answers here:
Stopping a Thread in Java? [duplicate]
(3 answers)
Closed 9 years ago.
I am trying to create a thread for a specific task to run in another class. The thread is starting the task but when I try to stop the thread, it is not stopping. The thread continues till the loop. Could you please help me out.
Thread Class:
package com.development;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ThreadExample extends JFrame {
MyThread mt;
Thread th;
ThreadExample(){
JPanel p1 = new JPanel();
p1.setPreferredSize(new Dimension(400,400));
JButton b1 = new JButton("Start");
JButton b2 = new JButton("Stop");
b1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
mt = new MyThread();
th = new Thread(mt);
th.start();
}
});
b2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
th.interrupt();
}
});
p1.add(b1);
p1.add(b2);
this.getContentPane().add(p1);
this.pack();
this.setVisible(true);
}
public static void main(String arg[]) {
ThreadExample mt = new ThreadExample();
mt.setVisible(true);
}
public class MyThread implements Runnable{
private volatile boolean runnable=true;
DisplayMsg dm = new DisplayMsg("Cycle");
#Override
public void run() {
while(!Thread.currentThread().isInterrupted()) {
// TODO Auto-generated method stub
dm.show();
}
}
}
}
DisplayMsg class:
package com.development;
public class DisplayMsg {
private String dispMsg;
private boolean runnable;
DisplayMsg(String dispMsg){
this.dispMsg=dispMsg;
}
public void show() {
for(int t=0;t<100;t++) {
try {
System.out.println(dispMsg + t);
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Your DisplayMsg class loops for 100 seconds, and ignores interrupts. Indeed, when Thread.sleep() is interrupted, it resets the interrupt status, then throws an InterruptedException. Since you ignore the InterruptedException, the thread continues as if nothing happened.
public void show() {
for(int t=0;t<100;t++) {
try {
System.out.println(dispMsg + t);
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Don't ignore interrupts:
public void show() {
for(int t=0;t<100;t++) {
try {
System.out.println(dispMsg + t);
Thread.sleep(1000);
} catch (InterruptedException e) {
// re-interrupt the thread and stop looping
Thread.currentThread().interrupt();
return;
}
}
}
A much simpler design which achieves what you need is the following:
public class MyThread implements Runnable{
DisplayMsg dm = new DisplayMsg("Cycle");
#Override public void run() {
try { while(true) dm.show(); }
catch (InterruptedException e) { }
}
}
public class DisplayMsg {
...
public void show() throws InterruptedException {
for(int t=0;t<100;t++) {
System.out.println(dispMsg + t);
Thread.sleep(1000);
}
}
}
This will simply let the InterruptedException propagate and end MyThread, with no effort on your own.
When you catch the InterruptedException in your DisplayMsg class, the interrupted flag is reset.
It's fine to catch the exception, but if you need to subsequently know if the thread has been interrupted, you need to reset the flag by interrupting again with Thread.currentThread.interrupt(); in that catch block and break out of the loop / return.
I believe what is happening is that you need to be checking !Thread.currentThread().isInterrupted() before each sleep. You are calling show() in the method which will iterate for 100 seconds only then will the your while loop check to see if the thread is interrupted. Move your check for interrtuped to your show method and see if it sees the interrupted flag. As per the next answers you should also set the Thread interrupted flag when you catch the InterruptedException.