NullPointerException: Timertask Cancel and Object Disposing - java

This is my first time here. Please, excuse my bad English.
I am writing here to ask a question about TimerTask and collateral effects of object disposing.
Here is a simple example. This example shows a JFrame with a big button which starts a TimerTask. This task only writes a message, sleeps 6 seconds, and writes another message.
Every 10 secs (it's not important this fact) the task is executed.
If I click the button (when I know that the task is stopped and in the sleep method), the object writer (that let's us write a message) is set to null and the timer is cancelled.
Then, if I cancel the task, and an execution of this task is running, it can be thrown NullPointerException (remember that writer was set to null).
My question is: how can I avoid NullPointerException in this case? Catching it in the
run method of Timertask? or directly interrupting the task with interrupt method?
Thank you for your understanding.
public class CancelTimer extends JFrame{
public static void main(String[] args) {
new CancelTimer().setVisible(true);
}
Timer timer;
Writer writer;
public CancelTimer() {
super();
writer=new Writer();
timer= new Timer("timer");
timer.schedule(new TimerTask() {
#Override
public void run() {
try{
writer.print("Start and wait");
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
writer.print("Bye, bye!");
} catch (NullPointerException e){
System.out.println("NullPointerException due external disposing task!");
}
}
}, 3000, 10000);
JPanel panel = new JPanel(new BorderLayout());
JButton button= new JButton();
button.setAction(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
writer=null;
timer.cancel();
}
});
panel.add(button,BorderLayout.CENTER);
this.setContentPane(panel);
this.pack();
this.setSize(new Dimension(400,400));
}
private class Writer {
public void print(String text){
System.out.println("PRINT SOME TEXT: "+text);
}
}
}

If you don't set your writer to null, but instead use a boolean value to track whether or not your task is active, you can save the trouble of having to catch the NullPointerException.
Basically, track the state of whether or not you should be writing something some other way. Setting your writer to null is just silly, because, as you've noticed, it then requires you to catch and handle an exception. This is not what exceptions are for.

Related

SwingWorker calls a JFrame Class ..window shows nothing

class class1{
public class1(){//here is my GUI commants}
#Override
public void actionPerformed(ActionEvent evt) //this is my action performed from a jframe window
{
worker = new SwingWorker<Void, Void>(){//ia m creating a worker
protected WaitWindow waitWindow;
#Override
protected Void doInBackground() throws Exception {
waitWindow= new WaitWindow();//i call waitWindow class to pop up my new window with the progressBar
return null;
}
#Override
protected void done(){
waitWindow.CloseWaitWindow();
}
};
try{
String option = (String)serversList.getSelectedItem();
if (evt.getSource().equals(Button1))//when client presses button1
{
if(option.equals("icsd Server"))
{//here is my connection
Registry registry = LocateRegistry.getRegistry("localhost",1080);
icsdserver = (ICSDinterface)registry.lookup("RmiCheckICSD");
worker.execute(); //i am calling execute until the server return 0 this might take a long time
if (icsdserver.RequestForEntry("icsd",0)==0)
{
worker.cancel(true); //when server tell its all ok (with 0) i call cancel(true)
AddGrade d = new AddGrade(icsdserver,"icsd");
}
}
}
}
catch (RemoteException ex) {System.out.println(ex);}
catch (NotBoundException ex) {System.out.println(ex);}
}}
The Wait Window class follows
class WaitWindow extends JFrame //my WaitWindow Class
{
private JProgressBar bar ;
public WaitWindow(){
super("Wait Until Connection Is ready");
setSize(100,200);
bar = new JProgressBar();
bar.setIndeterminate(true);
bar.setPreferredSize(new Dimension(300,330));
add(bar);
getContentPane();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public void CloseWaitWindow()
{
removeNotify();
}
}
What am I doing wrong here? I want the wait Window to shown until server's RequestForEntry method return 0 this might take some time. Also there is no error with RMI connection.
You're blocking the Event Dispathing Thread, with the call to RequestForEntry, which should be within the doInBackground method of the SwingWorker, for example
public void actionPerformed(ActionEvent ev) //this is my action performed from a jframe window
{
try {
final String option = (String) serversList.getSelectedItem();
if (evt.getSource().equals(Button1))//when client presses button1
{
final WaitWindow waitWindow = new WaitWindow();
worker = new SwingWorker<Void, Void>() {//ia m creating a worker
#Override
protected Void doInBackground() throws Exception {
if (option.equals("icsd Server")) {//here is my connection
Registry registry = LocateRegistry.getRegistry("localhost", 1080);
icsdserver = (ICSDinterface) registry.lookup("RmiCheckICSD");
worker.execute(); //i am calling execute until the server return 0 this might take a long time
if (icsdserver.RequestForEntry("icsd", 0) == 0) {
worker.cancel(true); //when server tell its all ok (with 0) i call cancel(true)
AddGrade d = new AddGrade(icsdserver, "icsd");
}
}
return null;
}
#Override
protected void done() {
waitWindow.CloseWaitWindow();
}
};
}
} catch (RemoteException ex) {
System.out.println(ex);
} catch (NotBoundException ex) {
System.out.println(ex);
}
}
Swing is a single threaded framework and isn't thread safe. This means that anything the blocks the Event Dispatching Thread will prevent it from processing new events, including paint requests.
Swing components should also only be updated from within the context of the EDT, which is where SwingWorker comes in.
See Concurrency in Swing and Worker Threads and SwingWorker for more details

How do I run a terminate command on JFrame exit?

I know the basics behind trying to write code that terminates a thread, but I've run into a bit of a problem.
I've got a JButton in a JFrame GUI that launches the simulation I'm trying to animate. It is called in the ActionPerformed code of the JButton by
new AnswerWorker().execute();
The AnswerWorker class, in turn, extends SwingWorker so that the animation frame can be drawn while the GUI is still active.
public class AnswerWorker extends SwingWorker<String, Integer> {
protected String doInBackground() throws Exception
{
Threading threading = new Threading();
return null;
}
protected void done()
{
try {
JOptionPane.showMessageDialog(InputGUI.this, AMEC.unsuccesfulpercentage + "% of iterations had trucks that had to sleep over");
AMEC.unsuccesfulpercentage = 0;
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
To create a way of stopping the simulation thread, I created the class Threading, that calls the function that runs the simulation.
public class Threading extends Thread {
#Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
AMEC.runsimulation();
} catch (IOException ex) {
Logger.getLogger(InputGUI.class.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
Logger.getLogger(InputGUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
return;
}
}
Now, in the runsimulation() function, I initialize a JFrame, and I want to terminate the thread running the simulation if the JFrame is closed by clicking on its close button. How do I do this?
EDIT: all of the above code is called in a file InputGUI.java that contains all my GUI elements. The runsimulation function is in my main project file, AMEC.java
You could override the dispose() method on the JFrame to include a call to stop the thread
#Override
dispose(){
stopThread();
super.dispose();
}
How do I run a terminate command on JFrame exit?
add WindowListener to JFrame, from windowClosing event you have to call JFrame.setVisible(false) and then to call SwingWorker
after SwingWorker ended to terminate current JVM, to show a JOptionPane in the case that any exception raised, or to show JFrame again back to screen, required to change DefaultCloseOperation, to HIDE_ON_CLOSE

Updating the JPanel in a JFrame

I have a JFrame with a CardLayout component. I am using the CardLayout to switch between different JPanel's at different moments of the application execution. At some point I am using a SwingWorker Object to generate some XML files. In this time I want to display another JPanel in my window to tell the user to wait. On this JPanel I want to switch between 3 labels.
JLabel 1 would be : "Please wait."
JLabel 2 would be : "Please wait.."
JLabel 3 would be : "Please wait..."
Right now the code looks like this:
ConvertersWorker.execute();
CLayout.show(Cards, WAIT_PANEL);
Timer t =new Timer(500, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e) {
WaitPanel.SwitchLabels();
}
});
t.start();
while (!this.finishedConverting)
{
}
//After this im am executing other methods based on the generated XML files
The SwingWorker code:
SwingWorker<Boolean, Void> ConvertersWorker = new SwingWorker<Boolean, Void>() {
public Boolean doInBackground() {
Boolean result = RunConverters();
return result;
}
public void done() {
try {
finishedConverting = get();
} catch (InterruptedException ex) {
ex.printStackTrace();
} catch (ExecutionException ex) {
ex.printStackTrace();
}
}
} ;
The second JPanel is not even displayed because the JFrame blocks. It blocks because of the while loop but I don't know how to implement it differently. And also the method done() from the SwingWorker is never executed. If it were executed then the finishedConverting variable would have been set to true and the while loop would have stopped. Can anyone help me to find a better solution?
I know you solved this but that's happening because you are using just one thread, and it blocked because of the While, so you need to create a new thread to handle this
new Thread(){
public void run() {
//code here
}
}.start();
and to refresh the content of a JPanel you can use
myJpanel.doLayout();
or
myJpanel.repaint();
I removed the while loop and moved the code which was after the loop in another method which is executed in the done() method of the SwingWorker so now it works.

strange bug - how to pause a java program?

I'm trying to:
display a text in a jLabel,
wait for two seconds,
then write a new text in the jLabel
this should be simple, but I get a strange bug:
the first text is never written, the application just waits for 2 seconds and then displays the final text. here is the example code:
private void testButtonActionPerformed(java.awt.event.ActionEvent evt) {
displayLabel.setText("Clicked!");
// first method with System timer
/*
long t0= System.currentTimeMillis();
long t1= System.currentTimeMillis();
do{
t1 = System.currentTimeMillis();
}
while ((t1 - t0) < (2000));
*/
// second method with thread.sleep()
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {}
displayLabel.setText("STOP");
}
with this code, the text "Clicked!" is never displayed. I just get a 2 seconds - pause and then the "STOP" text.
I tried to use System timer with a loop, or Thread.sleep(), but both methods give the same result.
Just to provide more background on Andrew Thompson's comment: the EDT is responsible for handling gui updates. If you block it using Thread.sleep(...) those updates are blocked as well. That's why you don't see the first text - the EDT just can't do the update on the label.
Here's a runnable example which does what you're after. As Andrew Thompson's comment stated, a SwingWorker is a good way to approach this problem.
The basic principal is to never block the Event Dispatch Thread. That's the thread responsible for repainting the GUI and responding to user interaction, so if you do something computationally expensive on the EDT, your GUI will stop responding.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.ExecutionException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingWorker;
public class ButtonTest {
public static void main(String[] args) {
// create a frame and a button
JFrame frame = new JFrame();
final JButton button = new JButton("Button");
frame.add(button);
// add an action listener to the button
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
// change the button text right away
button.setText( "Clicked" );
// create a SwingWorker which simply waits 2000 milliseconds
// simulating a computation being performed
SwingWorker<String, Object> worker = new SwingWorker<String, Object>() {
#Override
public String doInBackground() {
// it's safe to call Thread.sleep( ) here
// doInBackground is executed on a separate worker
// thread
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
return "Done";
}
#Override
protected void done() {
// done() is executed back on the Swing thread
// so it's safe to updated the state of the button
try {
button.setText(get());
} catch (Exception e) { }
}
};
// run the worker
worker.execute();
}
});
frame.setSize( 300, 300 );
frame.setVisible( true );
}
}
You are messing with the event dispatcher thread.
That will cause un-expected UI behavior as you are seeing. If you plan to do these type of animations, make sure to read up on what #Andrew Thompson suggested and also, see if you can read this - Filthy rich clients
Better to use a Swing Timer as shown in curde-example below:(yes, it is crude, I did not worry about stopping the timer etc):
public class DelayTest extends JPanel{
JLabel messageLabel = new JLabel();
JButton actionButton = new JButton("Click Me");
String[] messages = {"Clicked", "Stop!"};
int i=0;
public DelayTest(){
super();
add(messageLabel);
add(actionButton);
actionButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
if(i<=1)
messageLabel.setText(messages[i++]);
}
});
timer.start();
}
});
}
}
Edit
Why not stop the Timer:
#Override
public void actionPerformed(ActionEvent evt) {
if (i <= 1) {
messageLabel.setText(messages[i++]);
} else {
((Timer)evt.getSource()).stop();
}
}
});

Why is it so hard to stop a thread in Java?

I've come again in one of THOSE situations where it is just impossible to stop/destroy/suspend a thread. .interrupt() doesn't do the trick and .stop() and .suspend() are deprecated.
Very simple example:
public class TimerThread extends Thread {
private JPanel colorPanel;
public TimerThread(JPanel colorPanel) {
this.colorPanel = colorPanel;
}
public void run() {
while (true) {
try {
Thread.sleep(1000);
colorPanel.repaint();
} catch (Exception ex) {
//do Nothing
}
}
}
}
What this does is repaint a certain JPanel every second to change its colour. I want to start and stop the thread like this from another class:
timer = new Thread(new TimerThread(colorPanel));
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer.start();
}
});
stopButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer.interrupt();
}
});
Obviously (?) this doesn't work... I know I could use a Timer, a SwingWorker or declare the timer as timer = new TimerThread(colorPanel); and use a boolean instead of "true" in the run method, but I've been asked to declare timer as a "Thread" and nothing else.
To my surprise (or is this that stupid?), even this didn't work:
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer = new Thread(new TimerThread(colorPanel));
timer.start();
}
});
stopButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer.interrupt();
timer = null;
}
});
So my question is simple: How do you make threads Start/Pause/Resume/Stop in Java?
when you get an interrupt you should start the cleanup and return a.s.a.p. (or at the very least reset the interrupted status)
while (true) {
try {
Thread.sleep(1000);
colorPanel.repaint();
} catch(InterruptedException e){//from sleep
return;//i.e. stop
} catch (Exception ex) {
//do Nothing
}
}
another way is to check Thread.interrupted() in the condition (but you'll need to reset the interrupted status in the catch of InterruptedException
however in swing you can use javax.swing.Timer to let an event run every so often and stop that with the api of that
javax.swing.Timer timer = new Timer(1000,new ActionListener() {
public void actionPerformed(ActionEvent e) {
colorPanel.repaint();
}
});
timer.setRepeats(true);
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer.start();
}
});
stopButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer.stop();
}
});
Try this:
public class TimerThread extends Thread {
private volatile boolean stop = false;
private JPanel colorPanel;
public TimerThread(JPanel colorPanel) {
this.colorPanel = colorPanel;
}
public void stopTimer() {
stop = true;
}
public void run() {
while (stop == false) {
try {
Thread.sleep(1000);
colorPanel.repaint();
} catch (Exception ex) {
//do Nothing
}
}
}
}
// Why new Thread(new TimerThread(...))?
// timer = new Thread(new TimerThread(colorPanel));
timer = new TimerThread(colorPanel)
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer.start();
}
});
stopButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
timer.stopTimer();
}
});
Also have a look at here to see how you can replicate stop now that it's deprecated.
You make them co-operate, basically. You have some shared flags to let them see what they should be doing, and whenever you would sleep, instead you wait on some shared monitor. Then when you want to control the thread, you set the appropriate flag and notify the monitor so that if the thread was waiting, it will wake up and notice that it should suspend/stop/whatever. Obviously you need to take the normal sort of care around shared state, using volatile variables, Atomic* objects or locking to make sure that every thread sees the updates made by every other thread.
Anything non-cooperative is risky due to the chance of corrupting state half way through an operation.
It is dangerous to stop threads pre-emptively. Doing so leads to deadlocks, resource leaks and so on. Instead you should use a cooperative signaling mechanism.
Signal to the thread that you want it to stop, and then wait for it to do so. The thread should regularly check whether it needs to stop and react accordingly.
Instead of looping while (true), you should loop while the thread is not interrupted:
#Override public void void() {
// some kind of initialization...
while (!Thread.currentThread().isInterrupted()) {
try { ...
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // ensure interrupt flag is set
}
}
// some kind of cleanup
}
If InterruptedException is not thrown by anything inside your while block, either you don't use blocking operations (and simply calling Thread.interrupt() on this thread would stop it the next iteration) or you use some blocking calls that are not well behaved (there are many such examples in the JCL itself!).
The correct way to do this is indeed to have a variable that determines when the Thread should be stopped, exiting from its run method. You can find more information about how to do this properly here
With this solution you won't get "instantaneous" updates that you could get with wait/notify or interrupt, but if you don't mind the fraction of a second delay, it should do the job.
volatile boolean stopped = false;
volatile boolean paused = false;
pauseButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
paused = true;
}
});
resumeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
paused = false;
}
});
stopButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
stopped = true;
}
});
... TimerThread
public void run() {
while (stopped == false) {
try {
Thread.sleep(1000);
if (stopped)
break;
if (!paused)
colorPanel.repaint();
} catch (Exception ex) {
//do Nothing
}
}
}

Categories