Help with Swing threading!

B

buunguyen

I've got an interesting problem and cannot understand why it happens
this way.

I have a class to encapsulate the set "waiting" cursor.
public class CursorAction {
public CursorAction() {
Cursor currentCursor = getCursor();
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
execute();
setCursor(currentCursor);
}

protected void execute(){}
}

I use it as follows:
handleForButtonClick() {
new CursorAction() {
protected void execute() {
server.start();
}
};
}

The above code always throws an exception at the line server.start().
The exception is:

AWT-EventQueue-0Exception in thread "AWT-EventQueue-0"
java.lang.NullPointerException

But if I do this then it's always fine:

handleForButtonClick() {
Cursor currentCursor = getCursor();
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
server.start();
setCursor(currentCursor);
}

This is really strange because I believe that the 2 code segments do
the same thing. With my understand about threading in Swing/Awt and
anonymous class, I really don't understand why it happens this way.
Anyone has any idea?
 
N

NullBock

I don't think you've posted enough code. What is "server"--it has to
be a field, but of which class?

In any case, it appears that you're running into a problem with a
partially-constructed object. An object is only complete once its
constructor returns, and yet your base class is calling a method, meant
to be overridden, *before* the ctor returns. This is typically
dangerous to do--ctors should almost never call methods that will be
overridden--probably never.


Walter Gildersleeve
Freiburg, Germany

______________________________________________________
http://linkfrog.net
URL Shortening
Free and easy, small and green.
 
R

Roedy Green

Cursor currentCursor = getCursor();
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
server.start();
setCursor(currentCursor);

I presume server.start is not just starting a thread. It is some
action that takes noticeably time and you are willing to freeze the
entire gui during the time it runs.

Normally you would not use a wait cursor, but instead would do that
work on a separate worker thread so that gui could remain responsive.
 
B

buunguyen

'server' is an instance field of the class which has the posted code,
it is not a Runnable, the start() simply performs some kind of heavy
calculation.
 
B

buunguyen

Walter, I look at the generated code for the anonymous class and I'm
sure you're right, the 'server' instanced passed to the subclass is not
yet initialized. Thanks for pointing out.
 
T

Thomas Hawtin

I've got an interesting problem and cannot understand why it happens
this way.

I have a class to encapsulate the set "waiting" cursor.
public class CursorAction {
public CursorAction() {
Cursor currentCursor = getCursor();
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
execute();

It's usually a very bad idea to call overridable methods (on this) from
a constructor.
setCursor(currentCursor);
}

protected void execute(){}
}

I use it as follows:
handleForButtonClick() {
new CursorAction() {
protected void execute() {
server.start();

Even System.out.println(server); should NPE!.
System.out.println(MyOuterClass$this); should print "null".

I think I see what is going on. It's a bit subtle. Using -target 1.4
should cure the problems.

When an object is created, the constructor must be called before any
other methods. A constructor must call a constructor of the superclass
before any accesses to this. For the implementation of inner classes,
that means the outer this cannot be set before calling the
superconstructor. In your example the superconstructor calls a method
that uses the subclass outer this, which is at that point null. Oops.

In 1.4 a small change was made to the JVM spec to allow for setting the
outer this before calling the constructor (in most situations). For
backward compatibility javac will only generate code to do this if the
target is set to at least 1.4.

Tom Hawtin
 
B

buunguyen

Tom, it works when "-target 1.4". Do you know how it works under the
hood? I look at the decompiled code but I cannot get any sense out of
it.
 
T

Thomas Hawtin

Tom, it works when "-target 1.4". Do you know how it works under the
hood? I look at the decompiled code but I cannot get any sense out of
it.

Consider a simplified source file:
class Outer {
{
new Object() { };
}
}

To see what's in the source use javap -c, rather the a to Java source
decompiler. aload_0 refers to this (in a non-static method). aload_1 is
initially the first argument. "<init>" with angles is the internal name
given to all constructors.

The pre 1.4 version:

Compiled from "Outer.java"
final class Outer$1 extends java.lang.Object{
Outer$1(Outer);
Code:
First it calls the superconstructor, this.Object().
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
Now it stores the argument in this.this$0 (i.e. Outer.this).
4: aload_0
5: aload_1
6: putfield #2; //Field this$0:LOuter;
And returns.
9: return

}

The 1.4+ version:

Compiled from "Outer.java"
final class Outer$1 extends java.lang.Object{
final Outer this$0;

Outer$1(Outer);
Code:
First it stores the argument in this.this$0 (i.e. Outer.this), despite
previously not being allowed to access this before calling super. 'this'
is unitialised.
0: aload_0
1: aload_1
2: putfield #1; //Field this$0:LOuter;
Now, with this.this$0 in place, it calls the superconstructor,
this.Object().
5: aload_0
6: invokespecial #2; //Method java/lang/Object."<init>":()V
And returns.
9: return

}

Tom Hawtin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top