編輯:一個用戶標記我的問題可能是這個問題的重復:“ What is the volatile keyword useful for ”,其標題是“What is the volatile keyword useful for?”。我讀了這個問題,但我不明白它與我的問題有什么關系。這是一個用兩個 .java 文件編寫的程序。我的問題涉及主要方法中的 if..else..。請注意在下面的代碼中,else {..} 中的單行被注釋掉了。我將這個程序稱為“版本 1”,我將在“版本 2”中將該行注釋掉的程序稱為該程序。// -------------// The code below is in IfElseBugProgram.javapublic class IfElseBugProgram { public static void main(String[] args) { MyJFrame terminal = new MyJFrame(); while (true) { String keyReleased = terminal.getKeyReleased(); if (! keyReleased.equals("") ) { System.out.print("@" + keyReleased); } else { // System.out.print("!" + keyReleased); } } }}// ----- //The code below is in file MyJFrame.javaimport javax.swing.JFrame;import java.awt.event.KeyEvent;import java.awt.event.KeyListener;import java.util.ArrayList;import java.util.List;public class MyJFrame extends JFrame implements KeyListener{ private List<KeyEvent> keyEventQueue; public MyJFrame() { keyEventQueue = new ArrayList<KeyEvent>(); this.addKeyListener(this); pack(); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); } public void keyPressed(KeyEvent e) { } public void keyTyped(KeyEvent e) { } public void keyReleased(KeyEvent keyEvent) { keyEventQueue.add(keyEvent); System.out.println("some key was released!" + keyEventQueue.size()); }我希望 if {...} 中的代碼在我按下鍵盤上的某個鍵后運行。也就是說,我希望 System.out.print("@" + keyReleased); 代碼在我按下一個鍵時立即運行。使用版本 1,我似乎永遠不會System.out.print("@" + keyReleased);被運行;控制臺中永遠不會打印“@1”或“@2”或“@3”等。對于版本 2(即 else {..} 塊中的代碼重新注釋),通常發生的是打印出“!”的打印語句。重復運行,直到我按下一個鍵。那時,諸如“@1”或“@2”之類的東西會被重復打印。有時發生的是我沒有得到“!” 也沒有打印出“@1”或“@2”?。ㄊ褂孟嗤脑创a?。﹩栴}:為什么System.out.print("@" + keyReleased);if {..} 塊中的行在版本 1 中不運行,但(通常)在版本 2 中運行?
2 回答

富國滬深
TA貢獻1790條經驗 獲得超9個贊
通過假定變量不會被并發線程修改,Java VM 可以優化連續的、非同步的加載。
如果你想在一個將被另一個線程更改的字段上進行自旋循環,你可以讓虛擬機通過將其標記為來確保每次讀取都能看到最新的更改volatile
:
private volatile List<KeyEvent> keyEventQueue;
對 volatile 字段 (§8.3.1.4) 的寫入發生在對該字段的每次后續讀取之前。
我不知道你的 V2 是否保證按照 JLS 工作,但System.out
PrintStream
每次寫入時都會同步,從而限制允許 VM 進行的優化。

瀟瀟雨雨
TA貢獻1833條經驗 獲得超4個贊
您遇到這種不可預測的行為的主要原因是因為您實際上創建了一個多線程程序,您在其中從event dispatching thread以外的線程訪問 Swing 組件。
具體行:
MyJFrame terminal = new MyJFrame();
啟動 Swing 事件調度線程但行(例如):
String keyReleased = terminal.getKeyReleased();
terminal
從主線程訪問(Swing 組件)。
來自Swing 包文檔:
一般來說,Swing 不是線程安全的。除非另有說明,否則所有 Swing 組件和相關類都必須在事件調度線程上訪問。
在繼續嘗試使此代碼工作之前,我建議您閱讀教程課程:Swing 中的并發。
添加回答
舉報
0/150
提交
取消