java可重入鎖、讀寫鎖、synchronized 和lock有什麼區別?用新的lock有什麼好處?你挙例說說

一、原子引用java

package com.example.mybaties;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;

import java.util.concurrent.atomic.AtomicReference;

/**
 * @DESCRIPTION 原子引用
 * @Author lst
 * @Date 2020-03-24 09:00
 */
public class AtomicReferenceDemo {


    public static void main(String[] args) {
        User z3 = new User("z3",22);
        User li4 = new User("li4",25);

        AtomicReference<User> atomicReference = new AtomicReference();

        atomicReference.set(z3);
        System.out.println(atomicReference.compareAndSet(z3,li4)+ "\t " + atomicReference.get().toString());
        System.out.println(atomicReference.compareAndSet(z3,li4)+ "\t " + atomicReference.get().toString());//主物理內存已經變成li4
        /**
         * true	 User(userName=li4, age=25)
         * false	 User(userName=li4, age=25)
         */


    }
}

@Getter
@ToString
@AllArgsConstructor
class User {

    String userName;

    int age;

}

二、可重入鎖api

package com.example.mybaties;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @DESCRIPTION 可重入鎖(也叫遞歸鎖)
 * 指的是同一線程外層脳數得到鎖以後,內層遞歸數仍然能獲取該鎖的代嗎,在同一個線程在外層方法英取的時候,
 * 在進入內層方法會自動獲取鎖也便是說,線程能夠進入一個任何它已經擁有的所同歩的代碼塊
 *
 *
 *   就是一個典型的可重入鎖
 *
 * 11invoked sendSms
 * 11#######invoked sendEmail
 * 12invoked sendSms
 * 12#######invoked sendEmail
 *
 *
 *
 * @Author lst
 * @Date 2020-03-23 14:48
 */

class Phone implements  Runnable{

    public synchronized void sendSms(){
        System.out.println(Thread.currentThread().getId() + "invoked sendSms ");
        sendEmail();
    }

    public synchronized void sendEmail(){
        System.out.println(Thread.currentThread().getId() + "#######invoked sendEmail ");
    }


    Lock lock = new ReentrantLock();//默認非公平鎖


    @Override
    public void run() {
        get();
    }

    public void get(){
        lock.lock();
        lock.lock();

        System.out.println(Thread.currentThread().getName() + "  invoked get() ");
        set();

        lock.unlock();
        lock.unlock();

    }

    public void set(){
        lock.lock();

        System.out.println(Thread.currentThread().getName() + "  ####invoked set() ");
        lock.unlock();
    }
}


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();
        System.out.println();
        System.out.println();

        Thread t3 = new Thread(phone,"t3");
        Thread t4 = new Thread(phone,"t4");
        t3.start();
        t4.start();

        /**
         * 14invoked sendSms
         * 14#######invoked sendEmail
         * 13invoked sendSms
         * 13#######invoked sendEmail
         *
         *
         *
         *
         *
         * t3  invoked get()
         * t3  ####invoked set()
         * t4  invoked get()
         * t4  ####invoked set()
         */
    }

}

三、讀寫鎖多線程

/**
 * @DESCRIPTION 讀寫鎖
 *多個線程同時讀一個資源關沒有任何問題,因此爲了知足併發量,讀取共享資源應該能夠同時進行
 * 可是若是有一個線程想去寫共享資源來,就不該該再有其它線程能夠對該資源進行讀或寫
 * 小總結
 *      讀-讀能共存
 *      讀-寫不能共存
 *      寫不能共存
 *
 *
 *      寫操做:原子(完整一致性)+獨佔,整個過程必須是一個完整的統一體,中間不能間斷
 *
 * @Author lst
 * @Date 2020-03-24 12:00
 */

class MyCache {  //資源類

    private volatile Map<String,Object> map = new HashMap<>();
    private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

    public void put(String key,Object value){
        //寫鎖
        rwLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"  正在寫入: " +key);
            //暫停一會線程
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            map.put(key,value);
            System.out.println(Thread.currentThread().getName()+"  寫入完成: " );
        }catch (Exception e){
            e.getMessage();
        }finally {
            rwLock.writeLock().unlock();
        }
    }

    public void get(String key){
        //讀鎖
        rwLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"  正在讀取: " +key);
            //暫停一會線程
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Object result =  map.get(key);
            System.out.println(Thread.currentThread().getName()+"  讀取完成: " + result);
        }catch (Exception e){
            e.getMessage();
        }finally {
            rwLock.readLock().unlock();
        }
    }

    public void clearMap(){
        map.clear();
    }


}

public class ReentranRreadWriteLockDemo {

    public static void main(String[] args) {
        MyCache myCache = new MyCache();

        for (int i = 0; i < 5; i++) {
            final String keyValue = String.valueOf(i);
            new Thread(() -> {
                myCache.put(keyValue,keyValue);
            },keyValue).start();
        }



        for (int i = 0; i < 5; i++) {
            final String keyValue = String.valueOf(i);
            new Thread(() -> {
                myCache.get(keyValue);
            },keyValue).start();
        }


     /* 0  正在寫入: 0
        0  寫入完成:
        1  正在寫入: 1
        1  寫入完成:
        2  正在寫入: 2
        2  寫入完成:
        3  正在寫入: 3
        3  寫入完成:
        4  正在寫入: 4
        4  寫入完成:
        0  正在讀取: 0
        1  正在讀取: 1
        2  正在讀取: 2
        3  正在讀取: 3
        4  正在讀取: 4
        0  讀取完成: 0
        1  讀取完成: 1
        2  讀取完成: 2
        3  讀取完成: 3
        4  讀取完成: 4
        */


     ShareResource shareResource = new ShareResource();

        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                shareResource.print5();
            }
        },"A").start();

        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                shareResource.print10();
            }
        },"B").start();


        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                shareResource.print15();
            }
        },"C").start();

    }

}

四、synchronized和lock有什麼區別?用新的lock有什麼好處?你挙例說說併發

/**
 * 題目: synchronized 和lock有什麼區別?用新的lock有什麼好處?你挙例說說
 * 一、原始構成
 *      synchronized是關字jvm層面,
 *          monitorenter(底層是經過monitor對象來完成,其實wait/ notify等方法也依 monitor對象只有在同步塊或方法中能源ait/ notify等方
 *          monitorexit
 *      Lock是具體類(java,utiL, concurrent. Locks.Lock)是api層面的鎖
 * 二、使用方法
 *      synchronized 不須要用戶去手動釋放鎖,當 synchronized代碼執行完後系統會自動讓線程釋放對鎖的佔用
 *      Reentrantlock則須要戶去手動釋放鎖,若沒有主動釋放鎖,就有可能致使出現死鎖現象。須要Lock()和unLock()方法配合try/ finally語句塊來完成
 * 三、等待是否可中斷
 *      synchronized 不可中斷,除非拋出異常或者正常運行完成
 *      Reentrantlock 可中斷,
 *                  1.設置超時方法 trylock( long timeout, Timeunit unit)
 *                  2. LockInterruptibly()放代碼塊中,調 interrupt()方法可中斷
 * 四、加鎖是否公平
 *      synchronized非公平鎖
 *      Reentrantlock 二者均可以,默認非公平鎖,構造方法能夠傳入 boolean值,true爲公平鎖, false爲非公平鎖
 *
 * 五、鎖綁定多個條件 Condition
 *      synchronized沒有
 *      Reentrantlock,用來實分組喚要喚的線程,能夠精確喚醒,而不是像 synchronized要麼隨機喚醒一個線程 要麼喚醒所有線程
 *
 *
 * 原始構成:synchronized是JVM層面的,底層經過monitorenter和monitorexit來實現的。Lock是JDK API層面的。(synchronized一個enter會有兩個exit,一個是正常退出,一個是異常退出(保證確定能夠退出))
 * 使用方法:synchronized不須要手動釋放鎖,而Lock須要手動釋放。
 * 是否可中斷:synchronized不可中斷,除非拋出異常或者正常運行完成。Lock是可中斷的,1.設置超時方法tryLock(long timeout,TimeUnit unit); 2. lockInterruptibly()方法放代碼塊中,調用interrupt()
 * 是否爲公平鎖:synchronized只能是非公平鎖,而ReentrantLock既能是公平鎖,又能是非公平鎖,構造方法傳入false/true,默認是非公平鎖false。
 * 綁定多個條件:synchronized不能,只能隨機喚醒。而Lock能夠經過Condition來綁定多個條件,精確喚醒。
 *
 *
 * 題目:多線程之按順序調用,實現A->B->C三個線程啓動,要求以下
 * AA打印5次,BB打印10次,CC打印15次
 * 緊接着
 * AA打印5次,BB打印10次,CC打印15次
 * 。。。。。。
 * 來10輪
 *
 */

class ShareResource{
    private int number = 1;//A:1   B:2    C:3
    private Lock lock = new ReentrantLock();
    private Condition c1 = lock.newCondition();
    private Condition c2 = lock.newCondition();
    private Condition c3 = lock.newCondition();

    public void print5(){
        lock.lock();

        try{

            //一、判斷
            while (number != 1){
                c1.await();
            }

            //二、幹活
            for (int i = 1; i <= 5 ; i++) {
                System.out.println(Thread.currentThread().getName()+"   " + i);
            }

            //三、通知
            number = 2;
            c2.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void print10(){
        lock.lock();
        try{

            //一、判斷
            while (number != 2){
                c2.await();
            }

            //二、幹活
            for (int i = 1; i <= 10 ; i++) {
                System.out.println(Thread.currentThread().getName()+"   " + i);
            }

            //三、通知
            number = 3;
            c3.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void print15(){
        lock.lock();

        try{

            //一、判斷
            while (number != 3){
                c3.await();
            }

            //二、幹活
            for (int i = 1; i <= 15 ; i++) {
                System.out.println(Thread.currentThread().getName()+"   " + i);
            }

            //三、通知
            number = 1;
            c3.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
相關文章
相關標籤/搜索