Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/379.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么我的代码不是线程安全的?_Java_Multithreading_Swing_Thread Safety_Event Dispatch Thread - Fatal编程技术网

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

Java 为什么我的代码不是线程安全的?,java,multithreading,swing,thread-safety,event-dispatch-thread,Java,Multithreading,Swing,Thread Safety,Event Dispatch Thread,我正在创建一个可以从文件加载关卡的游戏。这是在一个单独的线程上完成的,而其他所有操作都是在事件调度线程上完成的 我通过从一个非常大的测试文件加载来测试代码,结果表明,在加载级别时,事件调度线程有时没有响应 我似乎找不出原因。以下是我的一些代码: public class LevelSelectionWrapper extends GamePanel { ... private JList list; private File[] files; ... //

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

我通过从一个非常大的测试文件加载来测试代码,结果表明,在加载级别时,事件调度线程有时没有响应

我似乎找不出原因。以下是我的一些代码:

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);
    }
}
public class-LevelSelectionWrapper扩展游戏面板{
...
私人名单;
私有文件[]文件;
...
//锁定对象以进行同步
私有对象锁=新对象();
//可运行,用于从单独线程上的文件加载级别
私有可运行加载程序=新可运行(){
@凌驾
公开募捐{
已同步(锁定){
//从文件加载级别

List levels=LevelLoader.load(files);//我绝对建议去掉
lock
对象(以及相关的依赖项)。获取
actionPerformed()中的文件列表
并构造一个副本以传递给您的runnable。避免像您当前那样使用实例变量,如
文件
,因为这些变量不必要地跨线程共享

这些
synchronized
块对我来说是最有可能的罪魁祸首。如果这不能解决您的问题,我建议在您认为被阻止的区域周围添加一些
System.out.println()
调用,以查看到底哪个调用花费了这么长时间


也可以考虑使用,而不是自己构造一个新线程。这样可以在EDT中节省几次线程启动时间。< /P>什么是<代码>同步化(锁)

在这种情况下?对我来说,这似乎是一种不好的/不必要的同步使用。例如,在本地获取文件列表,构造一个副本,并将副本传递给加载程序,比使用共享对象更好,然后必须锁定它。如果我误解了它的用途,也许你可以详细说明一下。这只是这个应用程序中的EDT没有响应,或者系统的其他部分也没有响应?@Ralf:我只使用了两个线程,EDT和工作线程。在工作线程完成之前,EDT没有响应。还有其他地方可以让你在
锁上
同步
吗?发一封感谢信,这个答案非常有用!我决定使用
SwingWorkers
,到目前为止,事件分派线程还没有变得无响应。此外,由于锁已被解除,我现在可以在已有级别加载的情况下加载其他级别。很好!
synchronized
块是有用的工具,但通常有许多更干净、更优雅的解决方案来处理并发。请谨慎使用它们,并且尽可能将数据一次限制为一个线程。