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ここでは、一度に 1 つのスレッドだけがアクセスできるように、スレッドを安全にしようとしています。このプログラムを実行していると、ブロック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]

異なるスレッドがこれにアクセスして変更していvalueます。誰かが私になぜこれがそうなのか説明できますか? そして、このグローバル変数をスレッドセーフにする方法は?

4

2 に答える 2

10

各スレッドには独自のThreadSafeがあり、それぞれThreadSafeに独自の異なる がありvalueます。さらに、synchronizedメソッドは でロックされるthisため、それぞれThreadSafeがそれ自体でロックされ、スレッド間で共有されるメソッドはありません。これはスレッドの局所性と呼ばれ、スレッドの安全性を確保する最も簡単な方法です。:)

あなたが望むと思う実験を得るには、MyThreadそのコンストラクターがThreadSafe引数を取るように変更する必要があります(構築するのではなく)。次に、main メソッドで 1 つ作成し、構築時ThreadSafeにそれぞれに渡します。MyThread

于 2013-05-03T14:37:02.300 に答える
4

各 s にはクラスRunnableの独自のインスタンスがあるため、毎回同じ値を取得しています。ThreadSafe

それらすべてで同じクラスを共有したい場合は、 のインスタンスを 1 つだけ持って、ThreadSafeそれをすべてのジョブに渡す必要があります。以下を参照してください。前述AtomicLongのように、スレッドセーフな shared が必要な場合は、 an が適していますlong

また、あなたのMyThreadクラスはすべきではありません extend Thread。代わりにすべきimplements Runnableです。Thread既にimplements 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;
    }
    ...
于 2013-05-03T14:37:35.823 に答える