java - 为什么我的代码不是线程安全的?

标签 java multithreading swing thread-safety event-dispatch-thread

我正在创建一个可以从文件加载关卡的游戏。这是在单独的线程上完成的,而其他一切都在事件调度线程上完成。

我通过从一个非常大的测试文件加载来测试代码,结果发现在加载关卡时事件调度线程有时没有响应。

我似乎无法找出原因。这是我的一些代码:

public class LevelSelectionWrapper extends GamePanel {
    ...
    private JList list;
    private File[] files;
    ...
    //Lock object for synchronization
    private Object lock = new Object();
    //Runnable for loading levels from files on a separate thread
    private Runnable loader = new Runnable() {
        @Override
        public void run() {
            synchronized(lock) {
                //Load levels from files
                List<Level> levels = LevelLoader.load(files); // <-------------
                ...
                SwingUtilities.invokeLater(new ListUpdater());
            }
        }
    };
    ...
    private void createOpenFileButton(Container container) {
        final JFileChooser fc = ...
        ...
        //Create open button
        JButton openButton = new JButton("Open file");
        openButton.setFocusable(false);
        openButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int returnVal = fc.showOpenDialog(LevelSelectionWrapper.this);
                if(returnVal == JFileChooser.APPROVE_OPTION) {
                    synchronized(lock) { files = fc.getSelectedFiles(); }
                    //Load files on separate thread
                    new Thread(loader).start(); // <-------------
                }
            }
        });
        container.add(openButton);
    }
}

我在代码中添加了两个箭头:

  • 第一个是耗时的方法(当文件非常大时)。有时,事件调度线程在这段代码运行时没有响应。
  • 最后一个是调用runnable的地方。

最佳答案

我肯定会建议摆脱那个 lock 对象(以及相关的依赖项)。获取 actionPerformed() 中的文件列表并构造一个副本以传递给您的可运行对象。避免像现在这样使用 files 之类的实例变量,因为它们会不必要地跨线程共享。

这些 synchronized block 对我来说是最有可能的罪魁祸首。如果这不能解决您的问题,我建议在您认为被阻止的区域周围添加一些 System.out.println() 调用,以尝试准确查看正在接受哪些调用长。

也可以考虑使用 SwingWorkers而不是自己构建一个新线程。这可以在 EDT 中为您节省几个线程启动时间周期。

关于java - 为什么我的代码不是线程安全的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15604396/

相关文章:

java - 如果 ReentrantLock 已锁定,则等待但不锁定该锁

java - 如何在 java swing 中打印出可搜索的数字列表?

java - 稍后如何在循环中使用变量

java - Spring 可以在 finally block 中提交事务,并在 try block 中使用 RunTimeException

c# - 在 Windows 服务中执行任务循环的最佳方法

ios - 指定函数 block 是异步与同步的模式

java - 编码字符串是否有最大的 Base64 大小?

java - Android应用程序使用倒计时器在特定时间播放mp3文件

java - 无法使用最新的 JDK (1.7.0_45) 在新的 netbeans 7.4 上访问合成主题

java - 如何更改 JLabel 的位置?