java Java中的线程安全全局变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16361378/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Thread safe global variable in Java
提问by user2219247
I am trying to understand the thread safety mechanism in java and I need some help. I have a class:
我正在尝试了解 Java 中的线程安全机制,我需要一些帮助。我有一堂课:
public class ThreadSafe {
private Executor executor = new ScheduledThreadPoolExecutor(5);
private long value = 0;
public void method() {
synchronized (this) {
System.out.println(Thread.currentThread());
this.value++;
}
}
private synchronized long getValue() {
return this.value;
}
public static void main(String... args) {
ThreadSafe threadSafe = new ThreadSafe();
for (int i = 0; i < 10; i++) {
threadSafe.executor.execute(new MyThread());
}
}
private static class MyThread extends Thread {
private ThreadSafe threadSafe = new ThreadSafe();
private AtomicBoolean shutdownInitialized = new AtomicBoolean(false);
@Override
public void run() {
while (!shutdownInitialized.get()) {
threadSafe.method();
System.out.println(threadSafe.getValue());
}
}
}
}
Here I am trying to make the value
thread safe, to be accessed only by one thread at a time. When I am running this program I see that there is more than one thread operating on the value
even if I wrap it within the synchronized
block. Of course this loop will be infinite but its just an example, I am stopping this program manually after few seconds, so I have:
在这里,我试图使value
线程安全,一次只能由一个线程访问。当我运行这个程序时,我看到有多个线程在运行,value
即使我将它包装在synchronized
块中。当然,这个循环是无限的,但它只是一个例子,我在几秒钟后手动停止这个程序,所以我有:
2470
Thread[pool-1-thread-3,5,main]
2470
Thread[pool-1-thread-5,5,main]
2470
Thread[pool-1-thread-2,5,main]
Different threads are accessing and changing this value
. Can somebody explain to me why is this so? And how to make this global variable thread safe?
不同的线程正在访问和改变 this value
。有人可以向我解释为什么会这样吗?以及如何使这个全局变量线程安全?
回答by yshavit
Each thread has its own ThreadSafe
, and each ThreadSafe
has its own, different value
. Moreover, synchronized
methods lock on this
, so each ThreadSafe
is locking on itself -- and none of them are being shared among threads. This is called thread-locality, and it's the easiest way to ensure thread safety. :)
每个线程都有自己的ThreadSafe
,并且每个线程都有ThreadSafe
自己不同的value
. 此外,synchronized
方法 lock on this
,因此每个方法ThreadSafe
都锁定自己——并且它们都没有在线程之间共享。这称为线程局部性,它是确保线程安全的最简单方法。:)
To get at the experiment that I think you want, you'd need to change MyThread
such that its constructor takes a ThreadSafe
argument (instead of constructing one). Then, have the main method create one ThreadSafe
and give it to each MyThread
at construction time.
为了进行我认为你想要的实验,你需要改变MyThread
它的构造函数接受一个ThreadSafe
参数(而不是构造一个)。然后,让 main 方法创建一个ThreadSafe
并MyThread
在构建时将其分配给每个方法。
回答by Gray
You are getting the same value every time because each of your Runnable
s has its own instance of the ThreadSafe
class.
您每次都获得相同的值,因为您Runnable
的每个s 都有自己的ThreadSafe
类实例。
If you want them all to share the same class, then you are going to need to only have one instance of ThreadSafe
and pass it into all of your jobs -- see below. As mentioned, an AtomicLong
is the way to go if you want a thread-safe shared long
.
如果您希望它们共享同一个类,那么您将只需要拥有一个实例ThreadSafe
并将其传递到您的所有作业中——见下文。如前所述,AtomicLong
如果你想要一个线程安全的 shared , an是要走的路long
。
Also, your MyThread
class should notextend Thread
. It should instead implements Runnable
. Your code is working because Thread
already implements Runnable
. If you did myThread.interrupt()
it would not actually be interrupting the thread because it is the thread-pool threads that are calling your run()
method.
另外,你的MyThread
类应该不会extend Thread
。它应该相反implements Runnable
。您的代码工作,因为Thread
已经implements Runnable
。如果你这样做了,myThread.interrupt()
它实际上不会中断线程,因为它是调用你的run()
方法的线程池线程。
Something like the following would work:
像下面这样的东西会起作用:
ThreadSafe threadSafe = new ThreadSafe();
for (int i = 0; i < 10; i++) {
threadSafe.executor.execute(new MyRunnable(threadSafe));
}
...
private static class MyRunnable implements Runnable {
private final ThreadSafe threadSafe;
public MyRunnable(ThreadSafe threadSafe) {
this.threadSafe = threadSafe;
}
...