Javaのロックは何を知っていますか?

38126 ワード

Javaのロックは何を知っていますか?
公平と非公平の鍵
  • フェアロックとは、複数のスレッドがロックを申請する順序でロックを取得することを意味し、キューのように並んで、先に来てから着く.   コンカレント環境では、各スレッドはロックを取得すると、このロックメンテナンスの待機キューを表示します.空の場合、または現在のスレッドが待機キューの1番目である場合、ロックを占有します.そうしないと、待機キューに追加され、後でFIFOのルールに従ってキューから自分にフェッチされます.
  • 非公平ロックとは、複数のスレッドがロックを取得する順序が申請ロックの順序ではなく、後に申請されたスレッドが先に申請されたスレッドよりも優先的にロックを取得する可能性があることを意味する.高同時性の場合、優先度の反転や接現象を引き起こす可能性があります.非公平ロックは乱暴で、上から直接占有ロックを試み、失敗したら公平ロックのような方法を採用します.
    構築関数のbooleanタイプを指定して公平ロックまたは非公平ロックを得ることができ、デフォルトは非公平ロックです.非公平ロックの点は、スループットが公平ロックよりも大きいことです.synchronizedにとって、非公平ロックでもある.
    リエントロック
        とは、統一スレッド外層関数がロックを取得した後も、内層再帰関数はそのロックのコードを取得することができ、同じスレッドが外層メソッドがロックを取得すると、内層メソッドに入ると自動的にロックを取得することを意味する.すなわち、スレッドは、すでに所有しているロックが同期しているコードブロックのいずれかに入ることができる.
    ReentrantLock/synchronizedは典型的な再ロックであり、再ロックの最大の役割はデッドロックを避けることである.
    /**
     *   1:Synchronized          
     * t1 invoke sendSms()
     * t1 ####invoke sendEmail()
     * t2 invoke sendSms()
     * t2 ####invoke sendEmail()
     *
     *   2:ReentrantLock          
     * Thread-0 invoke get()
     * Thread-0 ----invoke set()
     * Thread-1 invoke get()
     * Thread-1 ----invoke set()
     *
     * @author chenxiaonuo
     * @date 2019-08-12 15:06
     */
    public class ReenterLockDemo {
    
        public static void main(String[] args) {
            Phone phone = new Phone();
            new Thread(() -> {
                phone.sendSms();
            }, "t1").start();
    
            new Thread(() -> {
                phone.sendSms();
            }, "t2").start();
    
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println();
            System.out.println();
            System.out.println();
    
            Thread t3 = new Thread(phone);
            Thread t4 = new Thread(phone);
    
            t3.start();
            t4.start();
        }
    
    }
    
    class Phone implements Runnable{
    
        public synchronized  void sendSms(){
            System.out.println(Thread.currentThread().getName() + " invoke sendSms()");
            sendEmail();
        }
    
        public synchronized  void sendEmail(){
            System.out.println(Thread.currentThread().getName() + " ####invoke sendEmail()");
        }
    
        Lock lock = new ReentrantLock();
        @Override
        public void run() {
            get();
        }
    
        public void get(){
            lock.lock();
            try{
                System.out.println(Thread.currentThread().getName() + " invoke get()");
                set();
            } finally {
                lock.unlock();
            }
        }
        public void set(){
            lock.lock();
            try{
                System.out.println(Thread.currentThread().getName() + " ----invoke set()");
            } finally {
                lock.unlock();
            }
        }
    }
    

    スピンロック
       スピンロック(spinlock):ロックを取得しようとするスレッドがすぐにブロックされないのではなく、ループ方式でロックを取得しようとする利点は、コンテキスト切替の消費を減らすことであり、欠点はループが小さいCPU
    /**
     *        
     *    CAS       ,A      myLock       5  ,B              ,  null,
     *            ,  A    B    。
     * @author chenxiaonuo
     * @date 2019-08-12 18:26
     */
    public class SpinLockDemo {
    
        //      
        AtomicReference<Thread> atomicReference = new AtomicReference<>();
    
        public void myLock(){
            Thread thread = Thread.currentThread();
            System.out.println(Thread.currentThread().getName() + " come in...");
    
            while (!atomicReference.compareAndSet(null, thread)){
    
            }
        }
    
        public void myUnlock(){
            Thread thread = Thread.currentThread();
            atomicReference.compareAndSet(thread, null);
            System.out.println(Thread.currentThread().getName() + " invoked myUnlock()");
        }
    
        public static void main(String[] args) {
            SpinLockDemo spinLockDemo = new SpinLockDemo();
    
            new Thread(() -> {
                spinLockDemo.myLock();
                //      
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                spinLockDemo.myUnlock();
            },"t1").start();
    
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            new Thread(() -> {
                spinLockDemo.myLock();
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                spinLockDemo.myUnlock();
            },"t2").start();
        }
    
    }
    

    排他ロック(書き込みロック)/共有ロック(読み込みロック)/反発ロック
    ≪排他ロック|Exclusive Locks|emdw≫:ロックは一度に1つのスレッドにのみ保持されます.ReentrantLock/synchronizedの場合は、排他的なロック共有ロックです.このロックは、複数のスレッドによって保持できます.ReentrantReadWriteLockのリードロックは共有ロックであり、ライトロックは排他ロックである.リード・ロックの共有ロックは、同時読み取りが非常に効率的であることを保証し、読み書き、書き込みのプロセスは反発します.
    /**
     *                   ,         ,              。
     *   ,              ,                     
     *    :
     *       -    
     *       -     
     *       -     
     * @author chenxiaonuo
     * @date 2019-08-14 11:02
     */
    public class ReadWriteLockDemo {
    
        public static void main(String[] args) {
            MyCache myCache = new MyCache();
    
            for (int i = 0; i < 5; i++) {
                final int temp = i;
                new Thread(() -> {
                    myCache.put(temp+"",temp+"");
                }, String.valueOf(i)).start();
            }
    
            for (int i = 0; i < 5; i++) {
                final int temp = i;
                new Thread(() -> {
                    myCache.get(temp+"");
                }, String.valueOf(i)).start();
            }
        }
    
    }
    
    class MyCache{
    
        private volatile Map<String,Object> map = new HashMap<>();
        private ReadWriteLock rwLock = new ReentrantReadWriteLock();
    
        public void put(String key, Object value){
            rwLock.writeLock().lock();
            System.out.println(Thread.currentThread().getName() + "     :" + key);
            //      
            try {
                TimeUnit.MILLISECONDS.sleep(300);
                map.put(key,value);
                System.out.println(Thread.currentThread().getName() + "     ");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                rwLock.writeLock().unlock();
            }
    
        }
    
        public void get(String key){
            rwLock.readLock().lock();
            System.out.println(Thread.currentThread().getName() + "     ");
            //      
            try {
                TimeUnit.MILLISECONDS.sleep(300);
                Object o = map.get(key);
                System.out.println(Thread.currentThread().getName() + "     :" + o);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                rwLock.readLock().unlock();
            }
    
        }
    }