当我在传统构造函数中启动新线程时,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() {
}
}
}
最佳答案
这里的问题是,在构造函数中启动线程甚至注册监听器都被认为是危险的。
说明:
内部类包含对其封闭类的引用,这意味着您在构造函数中启动的线程具有对构造函数返回之前 TimerClass
对象状态的引用。因此,新线程可能会看到一个部分构造的对象,其值已过时(在一个线程中是当前值,但在其他线程中不是当前值)。
一个简单的修复:
将构造函数设为私有(private),然后创建一个公共(public)的静态工厂方法来创建对象并启动线程。
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() {
}
}
}
这样,线程将看到一个完全构造的对象,并且线程安全性将被恢复(从而消除警告)。
关于java - Lambda 表达式中的 "Starting new Thread in constructor"警告 (NetBeans IDE),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28924678/