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
块是有用的工具,但通常有许多更干净、更优雅的解决方案来处理并发。请谨慎使用它们,并且尽可能将数据一次限制为一个线程。