2012-08-29 45 views
2

我在回答这个有趣的情况时遇到了this questionJava线程的意外行为

尝试这一块的设计糟糕的代码 -

import javax.swing.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

class abc extends JFrame implements ActionListener 
{ 

boolean button_clicked = false; 
JButton b1; 

abc(){ 
    this.setSize (400, 400); 
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    this.createUI(); 
} 

void createUI(){ 
    this.setLayout(null); 
    b1 = new JButton("Click here"); 
    b1.setSize(110,30); 
    b1.setLocation(10,210); 
    this.add(b1); 
    b1.addActionListener(this); 
} 

public boolean isButton_clicked() 
{ 
    return button_clicked; 
} 

public void setButton_clicked(boolean button_clicked) { 
    this.button_clicked = button_clicked; 
} 



public void actionPerformed(ActionEvent arg0) { 
    button_clicked = true; 
} 

} 

这里的主要方法。

class tempMain extends JFrame 
{ 

public static void main(String[] args) throws Exception 
{ 
    abc temp = new abc(); 
    temp.setVisible(true); 
    while(true) 
    { 
    // Thread.sleep(200); 
     if(temp.isButton_clicked()) 
     { 
      JOptionPane.showMessageDialog(null, "Hello"); 
      temp.setButton_clicked(false); 
     } 
    } 
} 
} 

当我跑这我的Windows 7机器上,什么都没有发生至少约一分钟(我没有后等待)后,我点击的按钮。

现在,只是做一个小的变化 -

Thread.sleep(200); // uncomment this from the main. 

令人奇怪的是,它的工作原理,并显示一条消息的JOptionPane。为什么消息不是第一次显示?

回答

2

令人惊讶的是,它工作并显示一个JOptionPane消息。为什么消息不是第一次显示?

button_clicked没有被标记为volatile,正在从不同的线程比主线程更新。由于回调是由事件处理程序线程完成的,除非button_clicked被定义为volatile boolean,否则主线程将不会看到更新。进入睡眠状态可能会让内存屏障被穿过,幸运的是主线程中的button_clicked被更新。

以下是一些更多reading about volatile以及为什么当我们处理多个线程时它很重要。


的另一个问题是,你有一个无限循环被喷涌消息System.out。这会在一段时间后完全阻止,因为控制台无法显示快速停止检查点击的行。

+0

更新:我删除了System.out.println()。即使没有这个问题,问题仍然存在。 – CodeBlue

+0

您能否解释一下 - “由于回调是由事件处理程序线程完成的,主线程不会看到更新”?据我所知,主要是调用abc类的方法,并应始终能够获取button_clicked的最新值。 – CodeBlue

+1

但是我们正在讨论可以在多个处理器上运行的多个线程,每个处理器都有自己的内存缓存。 Java需要被告知''button_clicked''需要在线程之间进行同步。这里有一些阅读:http://www.javamex.com/tutorials/synchronization_volatile.shtml – Gray