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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 22:45:00  来源:igfitidea点击:

Thread safe global variable in Java

javamultithreadingthread-safety

提问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 valuethread 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 valueeven if I wrap it within the synchronizedblock. 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 ThreadSafehas its own, different value. Moreover, synchronizedmethods lock on this, so each ThreadSafeis 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 MyThreadsuch that its constructor takes a ThreadSafeargument (instead of constructing one). Then, have the main method create one ThreadSafeand give it to each MyThreadat construction time.

为了进行我认为你想要的实验,你需要改变MyThread它的构造函数接受一个ThreadSafe参数(而不是构造一个)。然后,让 main 方法创建一个ThreadSafeMyThread在构建时将其分配给每个方法。

回答by Gray

You are getting the same value every time because each of your Runnables has its own instance of the ThreadSafeclass.

您每次都获得相同的值,因为您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 ThreadSafeand pass it into all of your jobs -- see below. As mentioned, an AtomicLongis the way to go if you want a thread-safe shared long.

如果您希望它们共享同一个类,那么您将只需要拥有一个实例ThreadSafe并将其传递到您的所有作业中——见下文。如前所述,AtomicLong如果你想要一个线程安全的 shared , an是要走的路long

Also, your MyThreadclass should notextend Thread. It should instead implements Runnable. Your code is working because Threadalready 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;
    }
    ...