使用布尔变量来停止线程

发布于 2024-12-14 13:52:55 字数 1758 浏览 2 评论 0原文

我正在学习一本 Java 书,在其中一个示例中,我看到了一些可疑的东西。

public class ThreadExample extends MIDlet {
    boolean threadsRunning = true; // Flag stopping the threads

    ThreadTest thr1;
    ThreadTest thr2;

    private class ThreadTest extends Thread {
        int loops;

        public ThreadTest(int waitingTime) {
            loops = waitTime;
        }

        public void run() {
            for (int i = 1; i <= loops; i++) {
                if (threadsRunning != true) { // here threadsRunning is tested
                    return;
                }

                try {
                    Thread.sleep(1000);
                } catch(InterruptedException e) {
                    System.out.println(e);
                }
            }
        }
    }

    public ThreadExample() {
        thr1 = new ThreadTest(2);
        thr2 = new ThreadTest(6);
    }

    public void startApp() throws MIDletStateChangeException {
        thr1.start();
        thr2.start();

        try {
            Thread.sleep(4000); // we wait 4 secs before stopping the threads - 
                                // this way one of the threads is supposed to finish by itself
        } catch(InterruptedException e) {
            System.out.println(e);
        }

        destroyApp();
    }

    public void destroyApp() {    
        threadsRunning = false;

        try {
            thr1.join();
            thr2.join();
        } catch(InterruptedException e) {
            System.out.println(e);
        }

        notifyDestroyed();
    }
}

由于它是一个MIDlet应用程序,当它启动时,会执行startApp方法。为了简单起见,startApp 方法本身调用 destroyApp,因此程序会销毁,停止线程并通知销毁。

问题是,使用这个“threadsRunning”变量是否安全?它在两个线程内和 destroyApp 方法中的使用是否会在某些时候引起任何麻烦?放在声明前面的“易失性”关键字是否有助于同步它?

I have a Java book I'm learning from and in one of the examples, I saw something suspicious.

public class ThreadExample extends MIDlet {
    boolean threadsRunning = true; // Flag stopping the threads

    ThreadTest thr1;
    ThreadTest thr2;

    private class ThreadTest extends Thread {
        int loops;

        public ThreadTest(int waitingTime) {
            loops = waitTime;
        }

        public void run() {
            for (int i = 1; i <= loops; i++) {
                if (threadsRunning != true) { // here threadsRunning is tested
                    return;
                }

                try {
                    Thread.sleep(1000);
                } catch(InterruptedException e) {
                    System.out.println(e);
                }
            }
        }
    }

    public ThreadExample() {
        thr1 = new ThreadTest(2);
        thr2 = new ThreadTest(6);
    }

    public void startApp() throws MIDletStateChangeException {
        thr1.start();
        thr2.start();

        try {
            Thread.sleep(4000); // we wait 4 secs before stopping the threads - 
                                // this way one of the threads is supposed to finish by itself
        } catch(InterruptedException e) {
            System.out.println(e);
        }

        destroyApp();
    }

    public void destroyApp() {    
        threadsRunning = false;

        try {
            thr1.join();
            thr2.join();
        } catch(InterruptedException e) {
            System.out.println(e);
        }

        notifyDestroyed();
    }
}

As it is a MIDlet app, when it's started, the startApp method is executed. To keep it simple, the startApp method itself calls destroyApp and so the program destroys, stopping the threads and notifying the destruction.

The question is, is it safe to use this 'threadsRunning' variable and would its use inside both threads and in the destroyApp method cause any trouble at some point? Would 'volatile' keyword put in front of the declaration help to synchronize it?

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

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

发布评论

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

评论(1

逆光下的微笑 2024-12-21 13:52:55

设置布尔值是原子的,并且在此示例中没有“读取然后修改”逻辑,因此在这种特定情况下不需要同步对变量的访问。

然而,该变量至少应该被标记为易失性的。

将变量标记为 volatile 不会同步线程对它的访问;它确保线程不会由于代码优化或值缓存而错过另一个线程对变量的更新。例如,如果没有 volatilerun() 内部的代码可能会在开始时仅读取一次 threadsRunning 值,缓存该值,然后每次在 if 语句中使用这个缓存的值,而不是再次从主内存中读取变量。如果 threadsRunning 值被另一个线程更改,则可能不会被拾取。

一般来说,如果您在多个线程中使用一个变量,并且其访问不同步,则应该将其标记为易失性。

Setting a boolean value is atomic, and there is no "read then modify" logic in this example, so access to the variable doesn't need to be synchronised in this particular case.

However, the variable should at least be marked volatile.

Marking the variable volatile does not synchronise the threads' access to it; it makes sure that a thread doesn't miss another thread's update to the variable due to code optimisation or value caching. For example, without volatile, the code inside run() may read the threadsRunning value just once at the beginning, cache the value, and then use this cached value in the if statement every time, rather than reading the variable again from main memory. If the threadsRunning value gets changed by another thread, it might not get picked up.

In general, if you use a variable from multiple threads, and its access is not synchronised, you should mark it volatile.

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