在这种情况下,volatile足够吗?

huangapple go评论69阅读模式
英文:

Is volatile enough in this case?

问题

以下是我的应用程序的启动/停止过程,启动/停止代码由单线程的ThreadPoolExecutor处理,因此我保证在同一时间只能有一个线程处于活动状态。

我在询问isRunning变量。将变量设置为volatile是否足够?
该变量将在不同的线程中访问(读取/修改),但一次只会有一个线程!

编辑:
添加了变量读取(startProcedure()stopProcedure()开头)。我忘记了那部分,我道歉。

编辑2:
我认为可能很难注意到,但startProcedure()stopProcedure()是用于创建线程使用的startQuerystopQuery - 可运行的函数。

public final class Work {

    private static final ThreadPoolExecutor processor = new ThreadPoolExecutor(1, 1,
            0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>1),
            new ThreadPoolExecutor.DiscardPolicy());
    private static final Runnable startQuery = Work::startProcedure
            stopQuery = Work::stopProcedure;

    private static boolean isRunning = false;

    private Work(){}

    private static void startProcedure(){
        ifisRunningreturn;
        isRunning = true;
        // <some code>
    }

    private static void stopProcedure(){
        if(!isRunningreturn;
        // <some code>
        isRunning = false;
    }

    // ------公共API

    public static void start(){
        processor.executestartQuery;
    }

    public static void stop(){
        processor.executestopQuery;
    }

}
英文:

Below is my app's start/stop procedure, start/stop code is handled by a single-threaded ThreadPoolExecutor, so I'm guaranteed there's only one thread can be active at the same time.

I'm asking about isRunning variable. Is making the variable volatile enough?
The variable will be accessed (read/modify) from different threads (but only one at the same time!)

EDIT:
Added variable reading (beginning of startProcedure() and stopProcedure()). I forgot about that part, my apologies.

EDIT2:
I think it may be hard to notice, but startProcedure() and stopProcedure() are functions used to create startQuery and stopQuery - Runnables used by threads.

public final class Work {

    private static final ThreadPoolExecutor processor = new ThreadPoolExecutor(1, 1,
            0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue&lt;&gt;(1),
            new ThreadPoolExecutor.DiscardPolicy());
    private static final Runnable startQuery = Work::startProcedure,
            stopQuery = Work::stopProcedure;

    private static boolean isRunning = false;

    private Work() {}

    private static void startProcedure() {
		if (isRunning) return;
        isRunning = true;
        //&lt;some code&gt;
    }

    private static void stopProcedure() {
		if (!isRunning) return;
        //&lt;some code&gt;
        isRunning = false;
    }

    //------Public API

    public static void start() {
        processor.execute(startQuery);
    }

    public static void stop() {
        processor.execute(stopQuery);
    }

}

答案1

得分: 2

首先,volatile 与“线程安全”关系甚微。volatile 关注的是可见性及其提供的相关保证;具体而言,它围绕着“happens-before”原则运作(尽管我不会深入探讨这个)。

您的情况有些有趣:您有一个单线程。因此,真正的问题是,作为 start 方法一部分的操作是否对接下来的 stop 方法可见?换句话说,ThreadPoolExecutor::execute 是否提供任何可见性保证?

在我看来,答案是:是的,您根本不需要使用 volatileThreadPoolExecutor 实现的 ExecutorService 表示:

> 内存一致性效果:在线程将 Runnable 或 Callable 任务提交给 ExecutorService 之前的操作先于该任务所执行的任何操作之前发生...

我理解的方式是:在启动线程中进行的操作将先于停止线程中进行的操作发生。但是,只有在 startstop 被依次调用(并等待)的情况下,才能提供此保证 - 就像您的示例中那样。一旦您更改内部实现,这将不起作用。

英文:

First of all, volatile has very little to do with "thread-safety". volatile is about visibility and the guarantees it offers around that; specifically it works around "happens-before" principle (I will not dive into this, though).

Your case is a little bit interesting: you have a single thread. So the real question is, are actions that are done as part of the start method visible to the next stop method? In other words does ThreadPoolExecutor::execute offer any visibility guarantees?

It seems to me the answer is: yes and you do not need volatile at all. The ExecutorService, that ThreadPoolExecutor implements says:

> Memory consistency effects: Actions in a thread prior to the submission of a Runnable or Callable task to an ExecutorService happen-before any actions taken by that task...

The way I interpret this is: actions that are done in the start thread will happen-before actions that are done in the stop thread. But this guarantee can only be made if start and stop are called (and wait) one after another - like in your example. As soon as you change the inner implementation, this will not work.

答案2

得分: 0

是的,volatile 关键字对您的用例足够好。

Java 中的 volatile 关键字用于将 Java 变量标记为存储在主内存中。更准确地说,这意味着每次读取 volatile 变量都将从计算机的主内存中读取,而不是从 CPU 缓存中读取;每次写入 volatile 变量都将写入主内存,而不仅仅是写入 CPU 缓存。

英文:

Yes volatile keyword is good enough for your use case.

> The Java volatile keyword is used to mark a Java variable as being stored in main memory. More precisely that means, that every read of a volatile variable will be read from the computer's main memory, and not from the CPU cache, and that every write to a volatile variable will be written to main memory, and not just to the CPU cache.

huangapple
  • 本文由 发表于 2020年9月12日 21:36:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/63860881.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定