Reputation: 10153
I was working with java.net.Authenticator to create a blocking dialog that requests proxy login/password from the user first time any connection is established through proxy. Authenticator works just fine, but i got into some strange problem when i tried to synchronize the method that displays the input dialog.
Here is an abstract working code example of the problem i found:
private static JFrame frame;
public static void main ( String[] args )
{
frame = new JFrame ( "Frame" );
frame.add ( new JLabel ( "This is main application" ) );
frame.setSize ( 500, 500 );
frame.setLocationRelativeTo ( null );
frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
frame.setVisible ( true );
// Cycling thread
new Thread ( new Runnable ()
{
public void run ()
{
while ( true )
{
// Opening new dialog in a separate event dispatch thread
SwingUtilities.invokeLater ( new Runnable ()
{
public void run ()
{
showSomeLockingDialog ();
}
} );
// Wait 3 seconds before next window
try
{
Thread.sleep ( 3000 );
}
catch ( InterruptedException e )
{
e.printStackTrace ();
}
}
}
} ).start ();
}
private static final Object lock = new Object ();
private static void showSomeLockingDialog ()
{
synchronized ( lock )
{
// Output to see that this method is not finished yet
System.out.println ( "Method start" );
// Modal thread-blocking dialog
JDialog dialog = new JDialog ( frame, "Lock" );
dialog.add ( new JLabel ( "This should be blocking other dialogs" ) );
dialog.pack ();
dialog.setLocationRelativeTo ( null );
dialog.setModal ( true );
dialog.setVisible ( true );
// Output to see that this method is not finished yet
System.out.println ( "Method end" );
}
}
So basically:
So if you run this example you will see that each cycle a new dialog pops ignoring synchronization even if you do not close previous dialog. I have also tried simple method synchronization instead but it has the same effect.
Everything changes if we change the way we call showSomeLockingDialog() a bit:
new Thread ( new Runnable ()
{
public void run ()
{
showSomeLockingDialog ();
}
} ).start ();
(just using a separate thread instead of calling method inside event dispatch thread)
This way everything works the way i expect it to work - new dialog calls are blocked until the one that was called before is closed.
And that is pretty strange - what is so special about event dispatch thread that synchronization is getting ignored?
Or if it is actually a bug - is there any workaround? Maybe i am missing something huge...
Some thoughts: It seems to me that modal dialog setVisible method acts differently inside event dispatch thread (otherwise it would block the whole interface if called from there). But how does that affect synchronization...
P.S. And no, i can't just use 2nd (working) example in my specific case, because i am not calling that method where i want - it is getting called from random place, mostly from standart JDK classes (when any resource that is getting loaded from internet - either image in JLabel, some URL input stream or anything else).
Upvotes: 1
Views: 1214
Reputation: 1443
From the Dialog's setVisible javadoc documentation:
It is OK to call this method from the event dispatching thread because
the toolkit ensures that other events are not blocked while this method
is blocked.
And based on that java synchronized blocks are reentrant, the following is what is happening for each invokeLater:
showSomeLockingDialog
Since blocking is just for the setVisible and not for other events (ie. other invokeLaters) then you get the specified behavior.
Upvotes: 2