英文:
Is volatile enough in this case?
问题
以下是我的应用程序的启动/停止过程,启动/停止代码由单线程的ThreadPoolExecutor
处理,因此我保证在同一时间只能有一个线程处于活动状态。
我在询问isRunning
变量。将变量设置为volatile
是否足够?
该变量将在不同的线程中访问(读取/修改),但一次只会有一个线程!
编辑:
添加了变量读取(startProcedure()
和stopProcedure()
开头)。我忘记了那部分,我道歉。
编辑2:
我认为可能很难注意到,但startProcedure()
和stopProcedure()
是用于创建线程使用的startQuery
和stopQuery
- 可运行的函数。
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(){
if(isRunning)return;
isRunning = true;
// <some code>
}
private static void stopProcedure(){
if(!isRunning)return;
// <some code>
isRunning = false;
}
// ------公共API
public static void start(){
processor.execute(startQuery);
}
public static void stop(){
processor.execute(stopQuery);
}
}
英文:
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<>(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;
//<some code>
}
private static void stopProcedure() {
if (!isRunning) return;
//<some code>
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
是否提供任何可见性保证?
在我看来,答案是:是的,您根本不需要使用 volatile
。ThreadPoolExecutor
实现的 ExecutorService
表示:
> 内存一致性效果:在线程将 Runnable 或 Callable 任务提交给 ExecutorService 之前的操作先于该任务所执行的任何操作之前发生...
我理解的方式是:在启动线程中进行的操作将先于停止线程中进行的操作发生。但是,只有在 start
和 stop
被依次调用(并等待)的情况下,才能提供此保证 - 就像您的示例中那样。一旦您更改内部实现,这将不起作用。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论