当我在传统构造函数中启动新线程时,NetBeansIDE不会发出警告:
addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
(new SomeThread()).start();
}
});
但是如果我将它转换为Lambda表达式,我会收到警告"在构造函数中启动新线程":
addActionListener((ActionEvent e) -> {
(new SomeThread()).start();
});
这是什么问题?什么是正确的解决方案?
编辑1:
NetBeans IDE 8.0.2上的同样问题:
代码:
import java.awt.event.ActionEvent;
import javax.swing.Timer;
public class TimerClass extends Timer {
public TimerClass() {
super(1000, null);//Loop 1 sec
addActionListener((ActionEvent e) -> {
(new SomeClass()).start();
});
}
private class SomeClass extends Thread {
@Override
public void run() {
}
}
}
答案 0 :(得分:1)
这里的问题是,在构造函数中启动线程甚至注册侦听器被认为是危险的。
说明:
内部类包含对其封闭类的引用,这意味着您在构造函数中启动的线程在构造函数返回之前引用了TimerClass
对象的状态 。因此,新线程可能会看到具有过时值的部分构造的对象(在一个线程中是当前值但在其他线程中不是当前值)。
一个简单的修复:
使构造函数变为私有,然后创建一个创建对象并启动线程的公共和静态工厂方法。
import java.awt.event.ActionEvent;
import javax.swing.Timer;
public class TimerClass extends Timer {
// notice that the constructor is now private.
private TimerClass() {
super(1000, null); //Loop 1 sec
}
// This will create the instance and then register the listener and start the thread
public static TimerClass createInstance() {
TimerClass instance = new TimerClass();
instance.addActionListener((ActionEvent e) -> {
(instance.new SomeClass()).start();
});
return instance;
}
private class SomeClass extends Thread {
@Override
public void run() {
}
}
}
这样,线程将看到一个完全构造的对象,线程安全将被恢复(从而删除警告)。