views:

40

answers:

1

I am not clear about thread confinement. In swing all the gui components must be updated through the EDT. SwingWorker is provided in Java6 for lengthy operations, and in the done method the gui components can be updated. My understanding was that the gui components in the done() method are updated in the EDT. Therefore there should be no synchronization problems. But here link text

it says:

Because the ImageRetriever class will download an image and place it on a large label, providing the label and image URL in the constructor is convenient. ImageRetriever needs the URL to retrieve an image. Provide the label so that the ImageRetriever instance can set the label's icon itself. If you use inner classes, you might not even provide this information in the constructor, because the worker thread will be able to access the information directly. However, providing the information in the constructor helps your application to be more thread-safe because that information will not be shared among ImageRetriever instances

I am confused on this. If the SwingWorker methods update the gui components (in the example of the link the JLabel) in the EDT, why is it more thread-safe to not share them among ImageRetriever(=SwingWorker) instances? If we have multiple SwingWorkers and in the done() method they update the same component, we must use synchronization primitives for the update? Am I missunderstanding something? Doesn't thread-confinement mean that only 1 thread will do all the actions? Aren't swingworkers thread-confined?

Thanks

+1  A: 

If the label is declared in the parent class and for some reason a new value is assigned to that variable at some point, then all the swingworkers will see the update. Because this might happen while the EDT is updating things, it can lead to weird behaviors.

For instance:

SW in EDT - label.setText(...);
Thread1 - label = new JLabel();
SW in EDT - label.setIcon(...);

If the label variable is shared you will get an inconsistent state (label without text or icon).

Update Storing the label as a variable passed through the constructors is a way to avoid this issue. If you want to see changes but not in the middle of a method execution, on way is to use a method local variable. You assign it at the beginning of the method to make sure it's not going to be changed outside.

If you use inner classes and the attribute of the parent class this will look like this:

public void done() {
  JLabel l = label;
  l.setText(...);
  l.setIcon(...);
} 

If the variable is defined as an attribute of the SW, you will have to create some way of getting the value stored in the main class (eg. a getter)

Guillaume
@Guillaume: But in your example, the label is accessed by a thread outside of EDT which is not allowed. If in your example, the second line was missing (Thread1 - label = new JLabel(); ) and we hadSW in EDT - label.setText(...); SW in EDT - label.setText(...); is this thread-safe. My problem concerns a Jtree, not something as simple as a label
It's forbidden to call methods on components outside of the EDT but assigning a variable is allowed. Yes, it would be thread safe if no other operation is done on the component (no Thread1).
Guillaume
@Guillaume: One last question. If I pass the jlabel in the constructor of the SW then any change done by Thread1 will not be reflected in the SW done() method. Right? I mean SW will have a ref to a label, and thread1 will make label point to another label, but SW will have the old value. How would I go to make sure that the variables passed in the constructor, if changed, in the EDT we have the new value to use? If,I have a String variable that has the value "A" before calling SW.execute(); and after calling execute the variable has the value "B", how will this be visible in done()?