Java Forum / General / May 2007
Thread stuck in state NEW?
Mark Space - 24 May 2007 02:48 GMT Hi all, I was planning on doing some swing testing, but ran into a thread issue instead. The problem is a small anonymous thread class I create stays stuck in state NEW, even though it apparently runs an completes.
package crazythreads;
import javax.swing.JOptionPane;
public class Main { public static void main(String[] args) { Main test = new Main(); System.out.println( test.thready() ); }
private String thready() { String result = null; Thread t = new Thread(){ public void run() { //result = (String)JOptionPane.showInputDialog( JOptionPane.showInputDialog( null,"Enter a random string:"); } }; javax.swing.SwingUtilities.invokeLater(t); try { while( t.getState() == Thread.State.NEW ) // STUCK HERE Thread.sleep(100); while( t.getState() != Thread.State.TERMINATED) t.join(100); } catch( Exception ex) {ex.printStackTrace();} if( result == null ) return "No result."; return result; } }
The debugger shows the main thread stepping through the while loop at the comment STUCK HERE. The Thread, t, does run: I see it's dialog box come up, I enter a value and press OK. So it should at some point be in one of the running states (probably blocked on IO). Before adding the while loops, the main thread did not wait (at the t.join()) and just proceeded on to return "No Result." We can ignore the issues with result for now. ;-)
Anyone got any ideas? Being stuck in state NEW just confuses the heck out of me. Did I blow a conditional test somewhere?
Daniel Pitts - 24 May 2007 03:03 GMT > Hi all, I was planning on doing some swing testing, but ran into a > thread issue instead. The problem is a small anonymous thread class I [quoted text clipped - 47 lines] > Anyone got any ideas? Being stuck in state NEW just confuses the heck > out of me. Did I blow a conditional test somewhere? invokeLater is NOT what you want to do for Thread
invokeLater passes a Runnable object to be executed on the EventDispatchThread.
Thread happens to implement Runnable, so your code will get called on the EDT, but your thread object itself doesn't know or care about the EDT vs its self.
Generally, if you are updating the GUI, you want to create a Runnable (not thread) and use invokeLater, or invokeAndWait.
Although, I believe the JOptionPane calls are safe to call from any thread, so you don't need to create a new thread to do so. Double check the API doc before you take my word on that.
SadRed - 24 May 2007 03:13 GMT > > Hi all, I was planning on doing some swing testing, but ran into a > > thread issue instead. The problem is a small anonymous thread class I [quoted text clipped - 63 lines] > thread, so you don't need to create a new thread to do so. Double > check the API doc before you take my word on that. Daniel Pitts is right. OP's Thread t is never run, so it remains NEW state indefinitely. A thread that involeLater() would make, in which the JOptionPane is instantiated, is completely different from the Thread t of the Main class.
Mark Space - 24 May 2007 03:18 GMT > invokeLater is NOT what you want to do for Thread > > invokeLater passes a Runnable object to be executed on the > EventDispatchThread. Hmm, ok, I see what you mean. Considering all I'm doing is waiting, invokeAndWait makes sense. However, the other thing you are saying about Thread implementing Runnable: you mean Thread is bypassed, no .start() is called and all of it's state info is useless? Thats.. kinda weird. Anyone know, mechanically, how the EDT does this?
Later, JOptionPane will be replaced by a custom JFrame. It's just a placeholder in the example for now, so blocking or safe or not, it doesn't matter. I do need to return a value somehow, so that's next to work on.
Tom Hawtin - 24 May 2007 03:52 GMT > Although, I believe the JOptionPane calls are safe to call from any > thread, so you don't need to create a new thread to do so. Double > check the API doc before you take my word on that. No.
"Warning: Swing is not thread safe. For more information see Swing's Threading Policy."
("Swing's Threading Policy" shows you how to write code that doesn't compile:)
As it happens JDialog extends Dialog which has handling for being called off the EDT. So it may well appear to work. However, it's not safe at all.
Tom Hawtin
Daniel Pitts - 24 May 2007 20:03 GMT > > Although, I believe the JOptionPane calls are safe to call from any > > thread, so you don't need to create a new thread to do so. Double [quoted text clipped - 12 lines] > > Tom Hawtin Ah, actually what threw me off was the fact that JOptionPane modal dialogs block the current thread. automatically. I guess they push a new EDT thread onto some sort of stack to handle this case.
Tom Hawtin - 24 May 2007 21:50 GMT >> "Warning: Swing is not thread safe. For more information see Swing's >> Threading Policy."
>> As it happens JDialog extends Dialog which has handling for being called >> off the EDT. So it may well appear to work. However, it's not safe at all.
> Ah, actually what threw me off was the fact that JOptionPane modal > dialogs block the current thread. automatically. I guess they push a > new EDT thread onto some sort of stack to handle this case. It's behaviour implemented in Dialog (and other parts of AWT). There's Swing code in JOptionPane that is done entirely outside of that.
With modal Dialogs there are two ways it can go, depending upon whether it is in the EDT or not.
If a modal Dialog is shown off the EDT, the current thread just waits. (You can abuse this behaviour to do certain things from EDT thread that you otherwise shouldn't. However, EventQueue.isDispatchThread and the like will be inappropriate.) This should not be done with Swing components.
If a modal Dialog is shown on the EDT, a new event loop is run. That services events for the current dialog, and allows certain events through to other windows (repaints but not mouse motion, for instance).
IMO, modal user interfaces are poor anyway.
Tom Hawtin
Eric Sosman - 24 May 2007 03:11 GMT > Hi all, I was planning on doing some swing testing, but ran into a > thread issue instead. The problem is a small anonymous thread class I [quoted text clipped - 46 lines] > Anyone got any ideas? Being stuck in state NEW just confuses the heck > out of me. Did I blow a conditional test somewhere? The thread `t' never starts at all, hence remains forever in state NEW. The argument to invokeLater() is not a Thread per se, but a Runnable (Thread implements Runnable, which is why the code compiles). invokeLater() arranges for the run() method of its Runnable to be called by the Event Dispatching Thread, and its the EDT that displays your JOptionPane. But the "thread-ness" of t is never used; only its "runnable-ness" comes into play -- and on a different thread, at that.
What are you trying to accomplish with this JOptionPane? Yes, you said to "ignore the issues with result for now," but I suspect those very issues are central to finding the right solution.
 Signature Eric Sosman esosman@acm-dot-org.invalid
Tom Hawtin - 24 May 2007 03:26 GMT > Hi all, I was planning on doing some swing testing, but ran into a > thread issue instead. The problem is a small anonymous thread class I > create stays stuck in state NEW, even though it apparently runs an > completes.
> Thread t = new Thread(){
> javax.swing.SwingUtilities.invokeLater(t); SwingUtilities (or better java.awt.EventQueue) .invokeLater takes a Runnable argument, which by a piece of terrible design is implemented by Thread. It calls run on the argument, in the Event Dispatch Thread (EDT). In order for your thread to start, Thread.start would need to be called.
( You can pick up these sort of problems by using a subclass of Thread that does not allow itself to be used as a Runnable.
http://groups.google.com/group/comp.lang.java.programmer/browse_thread/thread/56 687253dbf9a11f/e634f82ccd1161a6?lnk=st&q=SafeThread&rnum=3#e634f82ccd1161a6 )
So, replace Thread with plain Runnable.
The easiest way to get the calling thread to wait is to use EventQueue.invokeAndWait instead of invokeLater, although it does add checked exceptions that need to be dealt with.
There are a number of ways to get results back from Runnable. The obvious way is to go one level up from an anonymous inner class and use a local class.
class InputDialogTask implements Runnable { String result; public void run() { result = (String)JOptionPane.showInputDialog( JOptionPane.showInputDialog( null, "Enter a random string:" ); } } InputDialogTask inputDialogTask = new InputDialogTask(); java.awt.EventQueue.invokeAndWait(inputDialogTask); return inputDialogTask.result;
If you don't mind being a little obscure, you can do it in a terser fashion.
return new Runnable() { String result; public void run() { result = (String)JOptionPane.showInputDialog( JOptionPane.showInputDialog( null, "Enter a random string:" ); } // (this is an instance initialiser) { java.awt.EventQueue.invokeAndWait(this); } }.result;
Alternatively, a more sophisticated approach is to have the main thread waiting on a (java.util.concurrent) blocking queue. This could be extended to make the main thread become event based (not shown).
final BlockingQueue<String> resultQueue = new ArrayBlockingQueue<String>(1); java.awt.EventQueue.invokeLater(new Runnable() { public void run() { String result = (String)JOptionPane.showInputDialog( JOptionPane.showInputDialog( null, "Enter a random string:" ); resultQueue.add(result); } }); return resultQueue.take(); // blocks
(Disclaimer: Not tested or even compiled.)
Tom Hawtin
Mark Space - 24 May 2007 04:03 GMT > Thread. It calls run on the argument, in the Event Dispatch Thread Ok, I think I get it. The EDT just calls run() directly, achieving synchronization by running the code in it's own thread. Gotcha. Now I understand why Thread was never invoked with start().
> There are a number of ways to get results back from Runnable. The > obvious way is to go one level up from an anonymous inner class and use > a local class. I'd thought of this, but I didn't have any need for a local class, and an anonymous class seemed to fit the overall design better.
> If you don't mind being a little obscure, you can do it in a terser > fashion. [quoted text clipped - 12 lines] > } > }.result; Wooooooow, smmmooooooottttthhhhh!! I'm highly impressed. Just the sort of trick I was looking for.
> Alternatively, a more sophisticated approach is to have the main thread > waiting on a (java.util.concurrent) blocking queue. This could be > extended to make the main thread become event based (not shown). I thought of this too, but declaring a concurrent object that going to be used once, for one piece of data, seemed a little "heavy weight" to me. It or the local class thing was going to be my "last ditch" effort.
Thanks for that great summary of ideas!!
Tom Hawtin - 24 May 2007 14:59 GMT > I thought of this too, but declaring a concurrent object that going to > be used once, for one piece of data, seemed a little "heavy weight" to > me. It or the local class thing was going to be my "last ditch" effort. IMO, using multiple threads is a bit heavyweight. Once you have multiple threads, BlockingQueue is remarkably lightweight (certainly beats playing with locks directly).
Tom Hawtin
Mark Space - 24 May 2007 16:56 GMT >> I thought of this too, but declaring a concurrent object that going to >> be used once, for one piece of data, seemed a little "heavy weight" to [quoted text clipped - 3 lines] > threads, BlockingQueue is remarkably lightweight (certainly beats > playing with locks directly). I do appreciate your replies; I'll describe briefly why. The code I posted was just a demo. In the final application, I'll already have multiple threads, plus the EDT, and I assume no choice but to synchronize with it. I don't see any other way. Any random thread might invoke the equivalent of "main," and then I'll have to put up a window, get a result, and return it to the random thread.
If you're referring to my initial use of the Thread class, yes, that was a conceptual error. ;-)
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|