为什么线程中的 Java 循环不起作用?

发布于 2024-12-04 01:27:26 字数 923 浏览 0 评论 0原文

我正在用java编写一个收音机,并且正在使用一个线程来播放流。我在线程的run方法中有一个while循环,它检查一个名为shouldPlay的变量是否为true,如果是,则运行玩家。然后,我有一个暂停()方法,它将变量设置为 false,自然我希望它在变量为 false 时不运行播放器。我创建了一个小例子来说明如何在下面进行设置:

class audiostream extends Thread {

    private boolean shouldPlay = true;

    @Override
    public void run() {
        while(true)
        { 
            if(shouldPlay)
            {
                shouldPlay = false;
                System.out.print("test");
            }
        }
    }

    public void pause() {
        shouldPlay = false;
    }

    public void play() {
        shouldPlay = true;
    }

}

我想要发生的是当线程首次运行时,它应该打印“test”(它做得很好)。然后,当您运行pause()时,它应该将shouldPlay设置为false并且不允许打印出“test”。但是当你调用 play() 时,它应该将 shouldPlay 设置为 true,然后再次打印出测试。问题是它没有这样做。

但大约有 1/100 的时间会发生。我是否正确地假设这里的问题是即使我从另一个线程调用 play() 和pause() 以免“挂起”父线程,但我的子线程挂在该 while 循环上并且在调用 play() 或从父级暂停()变量不会因为该循环而改变值?如果是这样我就不知道该怎么办了!

I'm coding a radio in java and am using a thread to of course play the stream in. I have a while loop in the run method of the thread which checks if a variable called shouldPlay is true, and if it is it runs the player. Then, I have a pause() method which sets the variable to false and naturally I want it to not run the player when the variable is false. I've created a small example of how I've set it up below:

class audiostream extends Thread {

    private boolean shouldPlay = true;

    @Override
    public void run() {
        while(true)
        { 
            if(shouldPlay)
            {
                shouldPlay = false;
                System.out.print("test");
            }
        }
    }

    public void pause() {
        shouldPlay = false;
    }

    public void play() {
        shouldPlay = true;
    }

}

What I want to happen is when the thread first runs, it should print "test" (which it does fine). Then when you run pause() it should set shouldPlay to false and not allow "test" to be printed out. But then when you call play() it should set shouldPlay to true then print out test again. The problem is it's not doing this.

About 1/100th of the time it will though. Am I right to assume the problem here is even though I call play() and pause() from another thread as not to "hang" the parent thread, that my child thread is hanging on that while loop and when calling play() or pause() from the parent the variables don't change value because of that loop? If that's the case I don't know what I should do!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

近箐 2024-12-11 01:27:26

添加“易失性”将修复它

private volatile boolean shouldPlay = true;

add 'volatile' will fix it

private volatile boolean shouldPlay = true;
最单纯的乌龟 2024-12-11 01:27:26

shouldPlay 应该是易失性,请删除 - shouldPlay = false;

if(shouldPlay)
 {
  //  shouldPlay = false;
      System.out.print("test");
 }

shouldPlay should be volatile and please remove - shouldPlay = false;,

if(shouldPlay)
 {
  //  shouldPlay = false;
      System.out.print("test");
 }
那片花海 2024-12-11 01:27:26

您可以使用 AtomicBoolean 作为替代方案。

You can make use of AtomicBoolean as an alternative.

欢你一世 2024-12-11 01:27:26

Java 内存模型仅保证线程在与其他线程同步时能够看到其他线程所做的更改。 Java 语言规范 定义 < em>同步如下:

同步动作引起动作上的同步关系,定义如下:

  • 监视器 m 上的解锁操作m 上的所有后续锁定操作同步(其中后续操作根据同步顺序定义) .
  • 对易失性变量的写入 (§8.3.1.4) v 与任何线程对 v 的所有后续读取进行同步(其中随后是根据同步顺序定义的)。
  • 启动线程的操作与它启动的线程中的第一个操作同步
  • 将默认值(零、假或空)写入每个变量每个线程中的第一个操作同步。虽然在分配包含变量的对象之前向变量写入默认值可能看起来有点奇怪,但从概念上讲,每个对象都是在程序开始时使用其默认初始化值创建的。
  • 线程 T1 中的最终操作与检测到 T1 的另一个线程 T2 中的任何操作同步 > 已终止。 T2 可以通过调用 T1.isAlive()T1.join() 来完成此操作。
  • 如果线程 T1 中断线程 T2,则 T1 的中断与任何其他点同步线程(包括 T2)确定 T2 已被中断(通过抛出 InterruptedException 或调用 Thread.interrupted > 或Thread.isInterrupted)。


在您的示例中,写入 shouldPlay 的线程和读取它的线程没有执行任何操作,因此无法建立同步。因此,未指定读取线程是否以及何时会注意到新值。

在您的情况下,声明 shouldPlay volatile 是建立同步的最简单方法。

The Java Memory Model only guarantees that threads will see changes made by other threads if they synchronize-with those threads. The Java Language Specification defines synchronized-with as follows:

Synchronization actions induce the synchronized-with relation on actions, defined as follows:

  • An unlock action on monitor m synchronizes-with all subsequent lock actions on m (where subsequent is defined according to the synchronization order).
  • A write to a volatile variable (§8.3.1.4) v synchronizes-with all subsequent reads of v by any thread (where subsequent is defined according to the synchronization order).
  • An action that starts a thread synchronizes-with the first action in the thread it starts.
  • The write of the default value (zero, false or null) to each variable synchronizes-with the first action in every thread. Although it may seem a little strange to write a default value to a variable before the object containing the variable is allocated, conceptually every object is created at the start of the program with its default initialized values.
  • The final action in a thread T1 synchronizes-with any action in another thread T2 that detects that T1 has terminated. T2 may accomplish this by calling T1.isAlive() or T1.join().
  • If thread T1 interrupts thread T2, the interrupt by T1 synchronizes-with any point where any other thread (including T2) determines that T2 has been interrupted (by having an InterruptedException thrown or by invoking Thread.interrupted or Thread.isInterrupted).

In your example, the thread writing shouldPlay and the thread reading it do none of that, thereby failing to establish synchronized-with. Therefore it is unspecified if and when the reading thread will notice the new value.

In your case, declaring shouldPlay volatile is the easiest way to establish that synchronization.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文