当前位置: 首页 > 知识库问答 >
问题:

当不同线程中的标志更改时循环未结束 [重复]

戎元忠
2023-03-14

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

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;

public class ThreadWhile implements KeyListener {
    private boolean flag = false;

    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("Looping until flag becomes true...");
        while(!tw.flag) {
            //Commenting the println out makes the loop run forever!
            System.out.println(tw.flag); 
        }
        System.out.println("Flag is true, so loop terminated.");
        System.exit(0);
    }

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

    public void keyReleased(KeyEvent e) {}
    public void keyTyped(KeyEvent e) {}
}

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

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

我猜这个问题可能是Java编译器试图将空while循环优化到停止检查“flag”变量的结果?有没有人有正确完成这项工作的建议,或者一些更好的基于并发的方法,让主线程暂停,直到被按键的线程执行?

谢谢!

共有3个答案

衡泰
2023-03-14

1.您需要为标志使用< code>volatile关键字,因为当我们对实例变量调用volatile时,就像告诉JVM确保访问它的线程必须将它自己的实例变量副本与存储在内存中的副本进行协调。

2.Volatile还有助于防止在线程中缓存值。

3.Volatile会使变量在一个线程中把它的变化值反映给另一个线程,但这并不妨碍竞争条件。

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

例如:

public void keyPressed(KeyEvent e) {
     synchronized(this){
        flag = true;
        System.out.println("flag: " + flag);
      }
    }
锺离马鲁
2023-03-14

虽然其他人提出的易失性解决方案应该可以工作,但除非你需要 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速度,并可能耗尽移动设备上的电池电量)。这正是 wait() 所针对的情况。

吴德辉
2023-03-14

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

 类似资料:
  • 我在php中工作,现在我正在将时循环应用于我的代码。我正在从数据库中获取数据。现在我必须将该数据应用于页面中的一个Div。 我的问题是"div类="项目活动"在循环中每次活动类都需要。现在我想改变它,就像在第一个循环过程之后,当第二个开始时,我想把那个div改变成这个"div类="项目"。 我对这个循环过程不太熟悉,所以我无法解决这个问题。需要帮助。谢谢

  • Python新手在这里。我正在编写一个简单的客户端/服务器程序,要求用户输入姓名、用户名、电子邮件地址、密码。此信息被发送到服务器,服务器将检查此用户的文本文件中是否已经有条目。如果有,它应该发送一条消息回来说这个用户已经存在,要求用户再试一次。 我设置了一个名为标志的变量为False。我对照文本文件检查用户信息,如果在文件中没有找到匹配,我将标志设置为true。然后我有一个if语句,它说如果标志

  • 问题内容: 继我以前的帖子在这里,我写了一个监听器: 目标 : 当我获得一秒或(进入循环时我已经获得一个/)时从循环中中断。 我是否需要将第二个侦听器附加到某物上? 但是我不能将其更改为false,因为它是在外部编写的。 即使将其更改为,也不能将其值更改为任何一个。 可以解决吗? 注意 :我已经有一个用于输入开关盒的按键监听器!! 编辑: 问题答案: 最终变量不能更改,但是如果它们表示可变对象,则

  • 线程的结束 现有问题 当内核线程终止时,会发生什么?如果就按目前的实现,我们会发现线程所执行的函数末尾会触发 Exception::InstructionPageFault 而终止,其中访问的的地址 stval = 0。 这是因为内核线程在执行完 entry_point 所指向的函数后会返回到 ra 指向的地址,而我们没有为其赋初值(初值为 0)。此时,程序就会尝试跳转到 0x0 地址,而显然它是

  • 程序从另一个类调用一个方法,这有助于更改程序的停止条件。它平均调用该方法3-8次,并且从未达到停止条件,但是它停止了。 示例类如下: 只限于在每个当的条件为false时,use示例类的当循环才会停止。这意味着: 它应该输出它经历了多少个同时循环以及每个循环的值。最终输出a1到e1的相同值。

  • 我有这个。。。我想知道如何用字母X结束循环。