不,这不是关于线程安全和添加密钥侦听器的一般问题:)
我在摆动中使用键侦听器打开和关闭布尔值时遇到了一个奇怪的问题:当按下和释放键时,我打开和关闭布尔值。在另一个线程中,我读取了布尔值并想用它做点什么。但不知何故,尽管布尔值的值必须为 true,但不知何故无法访问 if 块,因为我持有密钥。如果我向此部分添加断点,则会访问断点,或者如果我在 if 块中添加睡眠。为什么会这样?有人可以解释一下吗?
编辑:奇怪。使用原子布尔值可以解决这个问题。这可能是一把活锁吗?
package de.osipovan.rccontroller.gui;
import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class Test extends JFrame implements KeyListener {
private static final long serialVersionUID = -8395585938567486151L;
private JPanel contentPane;
private boolean doIt = false;
private Thread t = new Thread(new Runnable() {
@Override
public void run() {
while(true){
if(doIt){
System.out.println("done");
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
}
}
}
});
public Test (){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
t.start();
addKeyListener(this);
contentPane.addKeyListener(this);
setVisible(true);
}
@Override
public void keyTyped(KeyEvent e) {}
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_UP){
doIt = true;
}
}
@Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_UP){
doIt = false;
}
}
public static void main(String[] args) {
new Test();
}
}
我对线程不是很有经验,但我会说"doIt"不是线程安全的。
您也可以使用易失性:volatile private boolean doIt = false;
这将解决此问题。易失性使java总是从内存中重新读取值,而不是缓存或其他东西。
但这就是我所知道的。希望有人能给出更好的解释。
我更喜欢AtomicBoolean,因为我总是读到这样的话:"如果你真的不需要,就不要使用vol",这就是AtomicBoolean的目的。
我认为您可以将外部doIt变量与"Test.doIt"一起使用。
通常,使用 OuterClassName.this 来引用外部类的封闭实例。
我想你应该在thread()中尝试一个setter和一个局部变量。这可能需要一个新类。所以每次"doit"更改时,你都会喜欢classname.setBool(doit)。我不确定它是否有效,但这将是一个很好的开始:)