I have a button that starts a thread, which i use to show that my system is processing.
with thread1 i open a jdialog and to Show that my system is running. whereby i use thread2 to close my jdialog with dlg.dispose();
my problem is, once my program stops running, i click the button again, then an error message occurs, telling me that my thread has a problem.
I have another button without a thread behind and it performs the action perfectly if I click it another time.
Can somebody tell me where the problem is? I tried to close the thread by using Thread.currentThread().stop(); but it still does not work.
Here is my sample code,
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
if(chooser == null){
String message = "No file chosen. Please choose your file.";
JOptionPane.showMessageDialog(new JFrame(), message, "WiresharkHelper",
JOptionPane.ERROR_MESSAGE);
}
else if(chooser != null){
jTabbedPane4.setSelectedIndex(1);
thread1.start();
thread2.start();
}
}
JOptionPane opt = new JOptionPane("Application is running", JOptionPane.WARNING_MESSAGE, JOptionPane.DEFAULT_OPTION, null, new Object[]{});//I put this in global for my thread2 to dispose my dialog
JDialog dlg = opt.createDialog("Warning");
Thread thread2 = new Thread () {
public void run () {
dlg.setVisible(true);
}
};
Thread thread1 = new Thread () {
public void run () {
//code running
dlg.dispose();
}
};
Thread.currentThread().stop(); is #Deprecated JavaDoc
Try the following
Thread.currentThread().interrupt();
or
private volatile boolean stopRequested = false;
public void run() {
while (!stopRequested) {
...
}
}
public void requestStop() {
stopRequested = true;
}
My observations:
you are invoking Thread.currentThread().stop() on UI thread
itself, delete this line
thread2 is useless, delete it
invoke thread1 via SwingUtilities.invokeLater(thread1)
you are starting two threads and you have no way of saying, which will run first. I do not remember Swing that well now, but I would be surprised if first disposing dialog and then calling setVisible(true) would do something good
Related
tl, dr;
I have a GUI thread that creates an object of another class (the seconds class has implemented Runnable, but here we don't execute the run() method, instead, we call a normal method) and calls a method. In that method, the first thread (current thread) is called again (to show sth on the LCD), then sends some data to the Internet, and waits 3 seconds for the server response. The problem is that the information is printed after 3 seconds. I know about the stack and program counter, but I wonder if there is another option that I can do my job.
I have the main method, which runs 3 threads (for short, I just write the requisite code. Tell me to add more, if needed):
public static void main(String[] args) throws UnknownHostException, InterruptedException {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
GUI.getInstance().setVisible(true); //GUI is singleton, using swing and JFrame
} catch (Exception e) {
e.printStackTrace();
}
}
});
MQTTConnection.getInstance().tryToConnect(); //It's the connection class, which has a thread (the thread is handled by a library that keeps the connection alive. I have no threads there) and is a singleton too.
Thread t1 = new Thread(new SendDataThread()); //A thread which sends some data every 20 seconds.
t1.start();
}
And in SendDataThread, I have a function that creates some random data and sends them (using the MQTTConnection class).
This is the SendDataThread:
public class SendDataThread implements Runnable {
public void sendLog() {
boolean serverOnline = false;
StringBuilder data = new StringBuilder();
data.append(createData());
GUI.getInstance().printNeutral(data.toString()); //Prints BLACK on a `JTextPane`
if(MQTTConnection.getInstance().publishLog(MQTTConnection.getInstance().MQTT_PUBLISH_ESP_SEND_LOG, data.toString())) //This line has a 3 second timeout. If the server doesn't respond, it will return false. I've added the 3 seconds timeout too. Please continue reading.
serverOnline = true;
if(serverOnline)
GUI.getInstance().printOK("Server Submitted"); //Prints in GREEN
else
GUI.getInstance().printProblem("Check your connection!"); //Prints in RED
GUI.getInstance().printNeutral("-------------------------------------------------");
}
#Override
public void run() {
while(true) {
sendLog();
try {
Thread.sleep(20000); //sleeps 20 about seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//.....
}
And this is the 3 seconds timeout method, in MQTTConnection:
boolean publishLog(String topic, String data){
mqtt_responds = false;
publish(topic, data);
System.out.println("MQTT is connected");
long lastTime = System.currentTimeMillis();
while(System.currentTimeMillis() - lastTime < callback_timeout) {
if(mqtt_responds){
mqtt_responds = false;
System.out.println("Server submitted");
return true;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Timeout");
return false;
}
Till now, everything work right. The problem starts where I have a button in the GUI class, which the user can manually send random logs:
JButton sendLogBtn = new JButton("Send Log");
sendLogBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
SendDataThread sdt = new SendDataThread();
sdt.sendLog();
}
});
sendLogBtn.setBounds(10, 331, 89, 23);
panel.add(sendLogBtn);
This button creates an object of SendDataThread and calls the sendLog() method. The issue happens here: after sendLog() is called, sendLog(), calls this GUI thread again:
--> GUI.getInstance().printNeutral(data.toString()); //Prints BLACK on a `JTextPane`
But the log is printed after 3 seconds (After the sendLog() method has finished working, the timeout!)
How can I fix this?
In the button's actionPerformed you are calling sendLog. sendLog does exactly what you said, ie reports some logs and waits about 3 seconds (assuming callback_timeout is about equal to 3000).
To fix this, you need to make sure that the 3sec blocking is not on the EDT and also to make sure that the logs are instead posted on the EDT.
As a quick workaround you can do:
sendLogBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new Thread(() -> new SendDataThread().sendLog()).start();
}
});
and then, as always, post your logs in the EDT like for example:
SwingUtilities.invokeLater(() -> GUI.getInstance().printNeutral(...));
AND
SwingUtilities.invokeLater(() -> GUI.getInstance().printProblem(...));
AND
SwingUtilities.invokeLater(() -> GUI.getInstance().printOk(...));
As for the question in your comment, I don't really understand what you are asking, but I should say that (as far as I know) the EDT is a Thread where all the Swing code is (and should be) posted on for execution. This way the Swing code does not have to be synchronized, because all GUI related stuff is executed sequentially (on the EDT). AWT for example was not intended to be single threaded as far as I know. Swing is however single threaded.
I have a graphical user interface named Welcome, created with JFormDesigner. I want to wait until a button is clicked on that form before continuing my application.
I am doing this using synchronized and instancing the GUI as the object to wait for.
synchronized(new Welcome()) {
wait();
}
Inside of my GUI, I have a start button which when clicked runs this:
public void startScript() {
synchronized(this) {
notify();
}
// Close the GUI
dispose();
}
The GUI successfully loads however, I get this error:
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at dtohh.main.Main.(Main.java:20)
at dtohh.tests.Tests.main(Tests.java:11)
before I can even press the Start button on my GUI. When I then press the button, the script ends and does nothing more.
I added this to test if it was working correctly:
synchronized(new Welcome()) {
wait();
}
System.out.println("Test");
But after the button is pressed, the application exits and the output is not shown. How can I wait for the button to be pressed correctly?
I managed to figure it out, I need to wait on the Welcome.class instance and notify using this on the second thread.
Main thread:
Welcome gui = new Welcome();
syncronized(gui) { gui.wait(); }
Second thread:
private void onStart() {
syncronized(this) { notifyAll(); }
dispose();
}
This question already has answers here:
How to stop a java thread gracefully?
(6 answers)
Closed 9 years ago.
I create a thread in Java inside a button to print a simple message but I cannot stop it.
Thread a = new Thread();
a.start();
while(true){
try{
Thread.sleep(2000);
System.out.println("code");
}catch(Exception e){
}
}
when I click on it, itvstarts to print the code, but it seems to be blocked (the button). I would like to know. how can I stop the thread? And if I stop it, would be the button available again?.
I´m using netbeans 7.3, thanks.
while(true){
}
starts an infinite loop due to which all the other operations are blocked.
Remove that
Use interrupt(). Then handle the InterruptedException
The thread you are starting is not doing anything. It starts when you call a.start() and instantly terminates, because there is no code for this thread to run. Following this, the same thread that started the new one, and that is processing the click event, enters an infinite loop, so your user interface is completely blocked.
You need to give some code for the new thread to execute. To do so, you either pass the thread a Runnable or you override the thread's run() method. For example, to give it a Runnable containing the loop that prints every 2 seconds, you could do:
final Thread a = new Thread(new Runnable() {
#Override public void run() {
while (true) {
try {
Thread.sleep(2000);
System.out.println("code");
} catch (InterruptedException e) {
break;
}
}
}
};
a.start();
After that, if you ever want to stop that thread, you'd need to save a reference to the thread a in a field or something, and then call a.interrupt(). This will cause sleep to throw an InterruptedException, which will be caught and will execute break, which terminates the infinite loop and allows the thread to reach the end of the run method, which terminates the thread.
For example:
private Thread a = null;
... click handler on start button ... {
if (a == null) {
a = new Thread(new Runnable() {
#Override public void run() {
while (true) {
try {
Thread.sleep(2000);
System.out.println("code");
} catch (InterruptedException e) {
break;
}
}
}
};
a.start();
}
}
... click handler on "stop" button ... {
if (a != null) {
a.interrupt();
a = null;
}
}
You do not stop a thread in Java, you send an interrupt() signal.
The Thread may, or may no catch the signal. If it is waiting, or sleeping or joining (wait(), sleep() or join()) has been called on it), an InterruptedException will be raised.
The Thread (in its while loop) can test whether it has been interrupted by calling the isInterrupted() method and then decide to commit suicide (e.g. exit the loop).
In my application I have created one customized dialog box ,which is showed in both webview and normal android application,and also I doing some background operation when the dialog box is showed, when ever I called the mydialog function it shows my customized dialog box and also it return some values,it is perfectly working when I use webview+javainterface but it doesn't work with ordinary applications, the flow is
first I will get my dialog, after I do some process(here the main thread will wait ,dialog need to show,) then I will return the string ,the problem is dialog doesn't show when I called this function instead of that the dialog will showed after my background process finished.
I call this my dialog box like:
String sample=mydialog();
public String mydialog() {
String mystring = null;
try {
myactivity.this.runOnUiThread(ShowDialog);
while (customizeddialog.Getvalue() == null) {
}
mystring = customizeddialog.Getvalue();
customizeddialog.Setvalue(null);
} catch (Exception e) {
return mystring;
}
private Runnable ShowDialog = new Runnable() {
public void run() {
try {
customizeddialog m_dialog = new customizeddialog(myactivity.this);
m_dialog.setCancelable(false);
m_dialog.show();
} catch (Exception e) {
}
}
};
When you enter the synchronized block in mydialog() you acquire this's lock. Inside this synchronized block, you run ShowDialog() on the UI thread, and try to acquire this's lock again when you enter the synchronized block in ShowDialog.
Since the lock has already been acquired, it will wait until it is released in mydialog(), which will never happen because ShowDialog never executes past synchronized(this). What you have is deadlock.
I want to program a simple Snake.
Therefore I have programmed a custom JPanel, which can hold a Scene.
A Scene just draws something, and you can thread it with the public void run() method, so it implements Runnable.
Now, when I initialise the Scene, I create a Thread of the instance.
if (this.getThread() == null) {
Thread sceneThread = new Thread(this);
this.setThread(sceneThread);
this.getThread().run();
} else {
System.err.println("Scene is already running");
}
And the scene finally begins to be executed in a separate thread:
// Run thread
public void run () {
try {
while (true) {
this.update();
this.getGamePanel().sceneShouldRepaint();
Thread.sleep(this.getFps());
}
}
catch (Exception e) {
System.err.println(e);
}
}
Somehow this is blocking the windows thread.
It does not appear anymore.
Can anyone tell me why?
You are not starting the thread but directly invoke its run method, thus you are blocking the event thread itself in an endless loop - try starting it by calling start() instead.
Plus be sure to read about multithreading in Swing applications as pointed out by Qwerky.