我正在使用java.net.Authenticator创建一个阻止对话框,在通过代理建立任何连接时,首先从用户请求代理登录/密码。 Authenticator工作正常,但当我尝试同步显示输入对话框的方法时,我遇到了一些奇怪的问题。
这是我发现的问题的抽象工作代码示例:
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" );
}
}
基本上是这样的:
因此,如果运行此示例,即使您未关闭上一个对话框,也会看到每个循环都会弹出一个忽略同步的新对话框。我也尝试过简单的方法同步,但它具有相同的效果。
如果我们改变我们稍微调用showSomeLockingDialog()的方式,那么一切都会改变:
new Thread ( new Runnable ()
{
public void run ()
{
showSomeLockingDialog ();
}
} ).start ();
(仅使用单独的线程而不是在事件派发线程内调用方法)
这样一切都按照我期望的方式工作 - 新的对话框调用被阻止,直到之前调用的那个被关闭。
这很奇怪 - 事件调度线程的特殊之处在于同步被忽略了吗?
或者如果它确实是一个错误 - 是否有任何解决方法? 也许我错过了一些巨大的东西......
一些想法:在我看来,模态对话框setVisible方法在事件调度线程中的行为不同(否则如果从那里调用它会阻塞整个接口)。但这又如何影响同步......
PS 不,我不能只在我的具体情况下使用第二个(工作)示例,因为我没有调用我想要的方法 - 它是从随机地点调用的,主要是来自标准JDK类(当从Internet上加载任何资源时 - JLabel中的图像,某些URL输入流或其他任何内容)。
答案 0 :(得分:2)
来自对话框的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.
基于java synchronized块是可重入的,以下是每个invokeLater发生的情况:
showSomeLockingDialog
由于阻塞仅适用于setVisible而不适用于其他事件(即其他invokeLaters),因此您将获得指定的行为。