gpt4 book ai didi

java - 事件调度线程内的同步问题

转载 作者:行者123 更新时间:2023-11-30 04:47:28 25 4
gpt4 key购买 nike

我正在使用 java.net.Authenticator 创建一个阻止对话框,该对话框在第一次通过代理建立任何连接时请求用户提供代理登录名/密码。身份 validator 工作得很好,但是当我尝试同步显示输入对话框的方法时遇到了一些奇怪的问题。

这是我发现的问题的抽象工作代码示例:

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" );
}
}

所以基本上:

  1. 有一个可见的主框架(实际上只是为了保持JVM运行)
  2. 每个周期都有一个循环线程请求showSomeLockingDialog()方法
  3. 方法在“lock”对象上同步
  4. 方法开始和结束处有控制台输出

因此,如果您运行此示例,您将看到每个周期都会弹出一个新对话框,忽略同步,即使您不关闭先前的对话框也是如此。我也尝试过简单的方法同步,但效果相同。

如果我们稍微改变一下调用 showSomeLockingDialog() 的方式,一切都会改变:

    new Thread ( new Runnable ()
{
public void run ()
{
showSomeLockingDialog ();
}
} ).start ();

(仅使用单独的线程而不是在事件调度线程内调用方法)

这样一切都会按照我期望的方式工作 - 新的对话框调用将被阻止,直到之前调用的对话框被关闭为止。

这很奇怪 - 事件调度线程有什么特别之处以至于同步被忽略了?

或者如果它实际上是一个错误 - 有什么解决方法吗?也许我错过了一些巨大的东西......

一些想法:在我看来,模式对话框 setVisible 方法在事件调度线程内的行为有所不同(否则,如果从那里调用,它会阻塞整个界面)。但这如何影响同步......

P.S. 不,我不能在我的具体情况下只使用第二个(工作)示例,因为我没有在我想要的地方调用该方法 - 它主要是从随机位置调用的来自标准 JDK 类(当从互联网加载任何资源时 - JLabel 中的图像、某些 URL 输入流或其他任何内容)。

最佳答案

来自对话框的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 block)是可重入的,以下是每个 invokeLater 发生的情况:

  1. 调度线程正在调用 showSomeLockingDialog
  2. 获取锁定或重新进入
  3. 打开窗口 -> 阻塞直到关闭对话框

由于阻塞仅针对 setVisible 而不是针对其他事件(即其他 invokeLaters),因此您将获得指定的行为。

关于java - 事件调度线程内的同步问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10635343/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com