Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/374.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 当标志在不同线程中更改时,While循环未结束_Java_Multithreading_While Loop - Fatal编程技术网

Java 当标志在不同线程中更改时,While循环未结束

Java 当标志在不同线程中更改时,While循环未结束,java,multithreading,while-loop,Java,Multithreading,While Loop,我在Java程序的主方法中运行了一个while循环。循环应该一直运行,直到程序的keyPressed方法中的boolean标志变量设置为true(我将程序添加为JFrame的keylister) 我的理解是,keyPressed方法在它们自己的线程中执行,因此当我点击一个键时,变量'flag'应该设置为true,并且在main方法中运行的while循环应该结束 然而,当我运行这个程序时,循环将永远运行,即使我们可以看到'flag'变量被正确地设置为true!奇怪的是,如果我在while循环中插入

我在Java程序的主方法中运行了一个while循环。循环应该一直运行,直到程序的keyPressed方法中的boolean标志变量设置为true(我将程序添加为JFrame的keylister)

我的理解是,keyPressed方法在它们自己的线程中执行,因此当我点击一个键时,变量'flag'应该设置为true,并且在main方法中运行的while循环应该结束

然而,当我运行这个程序时,循环将永远运行,即使我们可以看到'flag'变量被正确地设置为true!奇怪的是,如果我在while循环中插入'flag'变量的快速System.out.println echo,程序就会正常运行,但显然我不想在循环中打印任何内容

我猜这个问题可能是由于Java编译器试图优化空while循环,直到停止实际检查'flag'变量?是否有人建议如何正确地执行此操作,或者是否有一些更巧妙的基于并发的方法使主线程暂停,直到按键线程执行为止


谢谢

您需要声明标志,否则编译器会优化您的代码并跳过对标志的读取。

虽然其他人提出的
volatile
解决方案应该可以工作,除非您需要While循环中的代码连续执行,否则您可能应该改用
wait()
notify()
(或
notifyAll()
)位于同步节内(以避免“忙等待”)。类似于:

public class ThreadWhile implements KeyListener {
    private boolean flag = false;
    private Object flagLock = new Object();

    public static void main(String[] args) {
        //Set up key listening on a dummy JFrame
        JFrame frame = new JFrame("Key Detector 9000");
        frame.setVisible(true);
        ThreadWhile tw = new ThreadWhile();
        frame.addKeyListener(tw);

        System.out.println("Waiting until flag becomes true...");
        synchronized (tw.flagLock) {
            while(!tw.flag)
                tw.flagLock.wait();   // Note: this suspends the thread until notification, so no "busy waiting"
        }
        System.out.println("Flag is true, so loop terminated.");
        System.exit(0);
    }

    public void keyPressed(KeyEvent e) {
        synchronized (flagLock) {
            flag = true;
            System.out.println("flag: " + flag);
            flagLock.notifyAll();
        }
    }

    ...

否则,您会在主线程上重复地浪费周期,反复检查
标志的值(通常,如果情况足够严重,会降低其他线程的CPU速度,并可能耗尽移动设备上的电池)。这正是
等待()的那种情况
是为.

1而设计的。您需要使用
volatile
关键字作为标志,因为当我们对实例变量调用volatile时,就像告诉JVM确保访问它的线程必须将其自身的该实例变量副本与存储在内存中的副本进行协调一样

2。Volatile也将有助于防止在线程中缓存值

3。Volatile将使该变量在一个线程到另一个线程中反映其已更改的值,但该不会阻止争用条件

4。因此,在设置标志值的原子语句上使用synchronized关键字。

例如:

public void keyPressed(KeyEvent e) {
     synchronized(this){
        flag = true;
        System.out.println("flag: " + flag);
      }
    }

太好了,这就解决了。谢谢!改用保护块()。循环并期望某些东西变成真的会破坏应用程序的性能并使其无响应。
public void keyPressed(KeyEvent e) {
     synchronized(this){
        flag = true;
        System.out.println("flag: " + flag);
      }
    }