Java中的线程安全全局变量

7

我希望你能帮我翻译一下与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());
            }
        }
    }

}

这里我试图使value线程安全,只能被一个线程访问。当我运行此程序时,即使我将其包装在synchronized块中,仍会有多个线程操作value。当然,这个循环将是无限的,但这只是一个例子,我在几秒钟后手动停止了这个程序,所以我有:

2470
Thread[pool-1-thread-3,5,main]
2470
Thread[pool-1-thread-5,5,main]
2470
Thread[pool-1-thread-2,5,main]

不同的线程正在访问和更改这个value。有人能解释一下为什么会这样吗?如何使这个全局变量线程安全?


你的意图是在这个例子中创建一个长静态吗?因为在其他情况下没有线程安全问题。 - Michal Borek
请注意我的回答。你的MyThread类不应该继承Thread,而应该实现Runnable接口。 - Gray
2个回答

10
每个线程都有自己的“ThreadSafe”,每个“ThreadSafe”都有自己不同的“value”。此外,“synchronized”方法锁定“this”,所以每个“ThreadSafe”都在其自身上锁定——它们之间没有共享。这被称为线程局部性,也是确保线程安全的最简单方法。 :)
要获取您想要的实验,您需要更改“MyThread”,使其构造函数接受一个“ThreadSafe”参数(而不是构建一个)。然后,让主方法创建一个“ThreadSafe”,并在构建时将其提供给每个“MyThread”。

4
每次都获得相同的值是因为每个Runnable都有自己的ThreadSafe类实例。如果想要它们共享相同的类,你需要只拥有一个ThreadSafe实例并将其传递给所有的任务——见下文。如上所述,如果你想要一个线程安全的共享long,那么AtomicLong就是最好的选择。
同时,你的MyThread类不应该是Thread的子类,而应该实现Runnable接口。你的代码之所以能够工作是因为Thread已经实现了Runnable接口。如果你调用myThread.interrupt(),它实际上不会中断线程,因为调用run()方法的是线程池线程。
以下示例代码可以正常工作:
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;
    }
    ...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接