スレッドセキュリティ(一)原子性ロックに基づく実装−synchronized修飾コードブロック

9837 ワード

ロックの概要
ロックはJavaの中でAtomicXXXクラスを除いて、もう一つの原子性を実現する方法であり、典型的な2つのロックに基づいて原子性を実現する方法はsynchronizedキーワードとLockインタフェースに基づく実現クラスである.
synchronizedキーワードロック
  • はJVMのロックに依存して実現され、synchronizedキーワードでロックされる.
  • synchronizedキーワードに加えられたロックは中断できないロックであり、競争が激しくなく、可読性が良いのに適している.
  • synchronizedキーワードに加えられたロックは、競争が激しい場合に性能が非常に低下する.

  • ロックインタフェースの実装クラス
  • は、JDKのjavaのような特殊なCPU命令に依存する.util.concurrent.locks.ロックインタフェースは、代表的な実装クラスにReentrantLockがあります.
  • Lockインタフェースの実装クラスプラスのロックは中断可能なロックであり、競争が激しい場合は常態を維持することができる.

  • synchronized修飾可能な4つのオブジェクト
  • 修飾コードブロック:修飾されたコードを同期文ブロックと呼び、その作用範囲は括弧で囲まれたコードであり、呼び出したオブジェクトに作用する(自分でロックオブジェクトを指定することができる).コードブロックがメソッド全体である場合、修飾方式と同等である.
  • 修飾方法:修飾された方法を同期方法と呼び、作用範囲は呼び出したオブジェクトに作用する方法全体である(this);
  • 静的方法を修飾する:作用範囲は静的方法全体であり、このクラスのすべてのオブジェクトに作用し、本質はClassオブジェクトに鍵をかける.
  • 修飾クラス:作用範囲はsynchronizedの後ろの括弧で囲まれた部分であり、このクラスのすべてのオブジェクトに作用し、本質はClassオブジェクトに鍵をかける.

  • synchronized修飾コードブロック例01-正例
  • 同じオブジェクトは異なるスレッドで同期コードブロックにアクセスし、同期コードブロックは同じ呼び出しオブジェクトに対して同期の役割を果たすことができる.
  • import lombok.extern.slf4j.Slf4j;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    @Slf4j
    public class SynchronizedCodeBlock {
    
        public void test1(int j) {
            synchronized (this) {
                for (int i = 0; i < 10; i++) {
                    log.info("synchronized block object {} - {}", j, i);
                }
            }
        }
    
        public static void main(String[] args) {
            testCodeBlockSync();
        }
    
        private static void testCodeBlockSync() {
            SynchronizedCodeBlock example1 = new SynchronizedCodeBlock();
            ExecutorService service = Executors.newCachedThreadPool();
            service.execute(() -> {
                example1.test1(1);
            });
            service.execute(() -> {
                example1.test1(1);
            });
        }
    
    }
    

    出力:
  • 同じオブジェクトが存在する2つのスレッドが順番に前後して実行される.
  • 17:06:51.597 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 0
    17:06:51.602 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 1
    17:06:51.602 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 2
    17:06:51.602 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 3
    17:06:51.602 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 4
    17:06:51.602 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 5
    17:06:51.602 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 6
    17:06:51.602 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 7
    17:06:51.602 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 8
    17:06:51.602 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 9
    17:06:51.602 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 0
    17:06:51.602 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 1
    17:06:51.603 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 2
    17:06:51.603 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 3
    17:06:51.603 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 4
    17:06:51.603 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 5
    17:06:51.603 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 6
    17:06:51.603 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 7
    17:06:51.603 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 8
    17:06:51.603 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 9
    

    synchronized修飾コードブロック例02-反例
  • 異なるオブジェクトは異なるスレッドで同期コードブロックにアクセスし、同期コードブロックは異なる呼び出しオブジェクトに対して同期の役割を果たすことができない.
  • import lombok.extern.slf4j.Slf4j;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    @Slf4j
    public class SynchronizedCodeBlock {
    
        public void test1(int j) {
            synchronized (this) {
                for (int i = 0; i < 10; i++) {
                    log.info("synchronized block object {} - {}", j, i);
                }
            }
        }
    
        public static void main(String[] args) {
            testCodeBlockNotSync();
        }
    
        private static void testCodeBlockNotSync() {
            SynchronizedCodeBlock example1 = new SynchronizedCodeBlock();
            SynchronizedCodeBlock example2 = new SynchronizedCodeBlock();
            ExecutorService service = Executors.newCachedThreadPool();
            service.execute(() -> {
                example1.test1(1);
            });
            service.execute(() -> {
                example2.test1(2);
            });
        }
    
    }
    

    出力:
  • 乱順で、2つのオブジェクトが存在するスレッドが同時に実行される.
  • 17:07:52.278 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 0
    17:07:52.278 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 0
    17:07:52.284 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 1
    17:07:52.284 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 1
    17:07:52.285 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 2
    17:07:52.285 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 2
    17:07:52.285 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 3
    17:07:52.285 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 3
    17:07:52.285 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 4
    17:07:52.285 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 4
    17:07:52.285 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 5
    17:07:52.285 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 6
    17:07:52.285 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 7
    17:07:52.285 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 5
    17:07:52.285 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 8
    17:07:52.285 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 9
    17:07:52.285 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 6
    17:07:52.285 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 7
    17:07:52.285 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 8
    17:07:52.285 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 9
    

    synchronized修飾コードブロック例03-run()メソッドのthisは誰ですか?
  • 回答:new Thread(instance)のinstanceです.
  • SynchronizedCodeBlock 02のrun()メソッドはthisにロックをかけ、t 1とt 2からのRunnableを作成するのはすべてinstanceであるため、スレッドt 1とt 2はいずれもinstanceにロックをかけるので、t 1とt 2の実行は同期することができる.
  • package com.example.concurrency.example.sync;
    
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    public class SynchronizedCodeBlock02 implements Runnable{
    
        static SynchronizedCodeBlock02 instance = new SynchronizedCodeBlock02();
    
        @Override
        public void run() {
            synchronized (this) {
                log.info("{} start",Thread.currentThread());
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("{} end",Thread.currentThread());
            }
        }
    
        public static void main(String[] args) {
            Thread t1 = new Thread(instance);
            Thread t2 = new Thread(instance);
    
            t1.start();
            t2.start();
    
            while (t1.isAlive() || t2.isAlive()) {
    
            }
            log.info("{} end", Thread.currentThread());
        }
    
    }
    

    出力:
    21:50:16.719 [Thread-0] INFO com.example.concurrency.example.sync.SynchronizedCodeBlock02 - Thread[Thread-0,5,main] start
    21:50:19.725 [Thread-0] INFO com.example.concurrency.example.sync.SynchronizedCodeBlock02 - Thread[Thread-0,5,main] end
    21:50:19.725 [Thread-1] INFO com.example.concurrency.example.sync.SynchronizedCodeBlock02 - Thread[Thread-1,5,main] start
    21:50:22.725 [Thread-1] INFO com.example.concurrency.example.sync.SynchronizedCodeBlock02 - Thread[Thread-1,5,main] end
    21:50:22.725 [main] INFO com.example.concurrency.example.sync.SynchronizedCodeBlock02 - Thread[main,5,main] end