Swing Thread安全编程

public static void main(String args[]) { /* Set the Nimbus look and feel */ // /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html */ try { for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { javax.swing.UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (ClassNotFoundException ex) { java.util.logging.Logger.getLogger(MyDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (InstantiationException ex) { java.util.logging.Logger.getLogger(MyDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (IllegalAccessException ex) { java.util.logging.Logger.getLogger(MyDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (javax.swing.UnsupportedLookAndFeelException ex) { java.util.logging.Logger.getLogger(MyDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } // /* Create and display the dialog */ java.awt.EventQueue.invokeLater(new Runnable() { public void run() { MyDialog dialog = new MyDialog(new javax.swing.JFrame(), true); dialog.addWindowListener(new java.awt.event.WindowAdapter() { @Override public void windowClosing(java.awt.event.WindowEvent e) { System.exit(0); } }); dialog.setVisible(true); } }); } 

MyDialog类只有很少的组合和文本字段,并且正在填充DB值的组合。 在选择一个组合值时,我从DB获取另一个值以填充下一个组合。

上述程序在不使用invokeLater线程的情况下以相同的方式运行。 什么时候invokeLater在Swing编程中变得有用。 我已经阅读了一些关于它的内容,但似乎都是理论上的。 invokeLater对应用程序有何不同? 仅仅在main方法中使用它还是应该在动作监听器中使用它是否足够?

SwingUtilities.invokeLater和java.awt.EventQueue.invokeLater – 它们是一样的吗?

没有什么理论上的。 这很实用。 SwingUtilities.invokeLater()方法保证Runnable中的代码将在Event Dispatch Thread (EDT) 。 这很重要,因为Swing不是线程安全的,因此任何与GUI( Swing等)相关的东西都需要在EDT上运行。 EDT是“只要它发生就会发生”线程,它不能保证执行事务的顺序。 如果GUI代码在后台线程中执行(例如,在SwingWorker实例中),那么它可能会抛出错误。 我学到了很多东西:在我学习的几年里,在后台线程中执行GUI更改代码导致了我无法理解的随机,不一致的RuntimeException 。 这是一个很好的学习经验( SwingWorker有一个用于后台任务的doInBackground()方法和一个用于EDT任务的done()方法)。

同样,您不希望在后台线程上执行GUI代码,您也不希望在EDT上执行大型操作(数据库查询等)。 这是因为EDT正在调度所有GUI事件,因此EDT上的所有内容都应该非常简短和甜蜜。 您可以使用JProgressBar设置为不确定来轻松查看此内容。

这个SSCCE应该很好地说明它。 注意JProgressBar作为method()被调用,一次在后台线程上,一次在EDT线程上。

 import javax.swing.JFrame; import javax.swing.JProgressBar; import javax.swing.SwingWorker; /** * * @author Ryan */ public class Test { public static void main(String args[]) { JFrame frame = new JFrame(); JProgressBar jpb = new JProgressBar(); jpb.setIndeterminate(true); frame.add(jpb); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); new Task().execute(); } public static void method() { // This is a method that does a time-consuming task. for(int i = 1; i <= 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(i); } } static class Task extends SwingWorker { @Override protected Void doInBackground() throws Exception { /* Executing method on background thread. * The loading bar should keep moving because, although method() is time consuming, we are on a background thread. */ method(); return null; } @Override protected void done() { /* Executing method on Event Dispatch Thread. * The loading bar should stop because method() is time consuming and everything on the Event Dispatch Thread * (like the motion of the progress bar) is waiting for it to finish. */ // method(); } } } 

希望这可以帮助。