顯示鎖Lock 和 AQS

Lock接口

主要方法:

Lock與 synchronized的比較

synchronized 代碼簡潔(關鍵字,是屬於語言層面實現同步)

Lock:獲取鎖可以被中斷,超時獲取鎖,嘗試獲取鎖,讀多寫少用讀寫鎖(是JDK提供的一個接口,來實現同步)

可重入鎖ReentrantLock

public class LockDemo {
    static Lock lock = new ReentrantLock();
    static int count;
    public void increase(int num){
        lock.lock();//獲取鎖
        try{
            count = count + num;
        }finally {
            lock.unlock();
        }
    }

    public synchronized void increase_syn(int num){
        count = count + num;
    }
    
    //synchronized方法調用另一個synchronized方法,可重入鎖,釋放鎖時,一個一個釋放
    public synchronized void syn2(int num){
        increase_syn(num);
    }
}

公平鎖和飛公平鎖

如果在時間上,先對鎖進行獲取的請求,一定先被滿足,這個鎖就是公平的,不滿足,就是非公平的

非公平的效率一般來講更高

ReentrantLock默認非公平鎖

ReadWriteLock

實現類:ReentrantReadWriteLock

同一時刻允許多個讀線程同時訪問,但是寫線程訪問的時候,所有的讀和寫都被阻塞

示例:ReentrantReadWriteLock 與 synchronized的對比

public class GoodServiceLock implements GoodService{
    private ReadWriteLock lock = new ReentrantReadWriteLock();
    private Lock readLock = lock.readLock();
    private Lock writeLock = lock.writeLock();
    private GoodInfo goodInfo;
    public GoodServiceLock(GoodInfo goodInfo){
        this.goodInfo = goodInfo;
    }

    @Override
    public GoodInfo getNum() {
        readLock.lock();
        try {
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return goodInfo;
        }finally {
            readLock.unlock();
        }
    }

    @Override
    public void setNum(int number) {
        writeLock.lock();
        try {
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            goodInfo.changeNumber(number);
        }finally {
            writeLock.unlock();
        }
    }
}

public class GoodServiceSyn implements  GoodService{
    private GoodInfo goodInfo;

    public GoodServiceSyn(GoodInfo goodInfo){
        this.goodInfo = goodInfo;
    }

    @Override
    public synchronized GoodInfo getNum() {
        try {
            Thread.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return this.goodInfo;
    }

    @Override
    public synchronized void setNum(int number) {
        try {
            Thread.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        goodInfo.changeNumber(number);
    }
}

public class GoodTest {
    private static int writeNum = 2;
    private static int readNum = 5;

    static class ReadGoodThread extends Thread {
        private GoodService goodService;

        public ReadGoodThread(GoodService goodService) {
            this.goodService = goodService;
        }

        @Override
        public void run() {
            long start = System.currentTimeMillis();
            for (int i = 0; i < 100; i++) {//操作100次
                goodService.getNum();
            }
            System.out.println(Thread.currentThread().getName() + "讀取商品數據耗時:"
                    + (System.currentTimeMillis() - start) + "ms");
        }
    }

    static class WriteGoodThread extends Thread {
        private GoodService goodService;

        public WriteGoodThread(GoodService goodService) {
            this.goodService = goodService;
        }

        @Override
        public void run() {
            long start = System.currentTimeMillis();
            Random r = new Random();
            for (int i = 0; i < 10; i++) {//操作10次
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                goodService.setNum(r.nextInt(10));
            }
            System.out.println(Thread.currentThread().getName()
                    + "寫商品數據耗時:" + (System.currentTimeMillis() - start) + "ms---------");

        }
    }

    public static void main(String[] args) {
        GoodInfo goodInfo = new GoodInfo(100000, 10000);
        GoodService goodsService = new GoodServiceSyn(goodInfo);
//        GoodService goodsService = new GoodServiceLock(goodInfo);
        for (int i = 0; i < writeNum; i++) {
            Thread setT = new Thread(new WriteGoodThread(goodsService));
            for (int j = 0; j < readNum; j++) {
                Thread getT = new Thread(new ReadGoodThread(goodsService));
                getT.start();
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            setT.start();
        }
    }
}

運行結果:

synchronized:

Thread-23讀取商品數據耗時:3112ms
Thread-7讀取商品數據耗時:3655ms
Thread-19讀取商品數據耗時:3749ms
Thread-9讀取商品數據耗時:4055ms
Thread-21讀取商品數據耗時:4033ms
Thread-11讀取商品數據耗時:4195ms
Thread-15讀取商品數據耗時:4330ms
Thread-17讀取商品數據耗時:4820ms
Thread-1寫商品數據耗時:4864ms---------
Thread-5讀取商品數據耗時:5116ms
Thread-3讀取商品數據耗時:5133ms
Thread-13寫商品數據耗時:4991ms---------

ReentrantReadWriteLock :

Thread-5讀取商品數據耗時:589ms
Thread-3讀取商品數據耗時:595ms
Thread-11讀取商品數據耗時:594ms
Thread-9讀取商品數據耗時:608ms
Thread-7讀取商品數據耗時:614ms
Thread-1寫商品數據耗時:605ms---------
Thread-21讀取商品數據耗時:614ms
Thread-19讀取商品數據耗時:619ms
Thread-15讀取商品數據耗時:641ms
Thread-23讀取商品數據耗時:639ms
Thread-17讀取商品數據耗時:649ms
Thread-13寫商品數據耗時:589ms---------

在讀多寫少的場景下,可以看出ReentrantReadWriteLock比synchronized的效率高出很多。

Condition

用Lock與Condition實現消息通知(類似與Obejct的wait、notify、notifyAll,但比這個更優,不會出現信號丟失的現象,一個Lock可以創建多個Condition,根據Condition的不同,分別進行await,signal、signalAll)

public class ConditionDemo {
    static String CITY = "xianyang";
    static Lock lock = new ReentrantLock();
    static Condition siteCondition = lock.newCondition();
    static Condition kmCondition = lock.newCondition();

    private String site;
    private  int km;


    public ConditionDemo(String site, int km) {
        this.site = site;
        this.km = km;
    }

    /* 變化公里數,然後通知處於wait狀態並需要處理公里數的線程進行業務處理*/
    public void changeKm(){
        lock.lock();
        try {
            this.km = 101;
            kmCondition.signal();
        }finally {
            lock.unlock();
        }
    }

    /* 變化地點,然後通知處於wait狀態並需要處理地點的線程進行業務處理*/
    public  void changeSite(){
        lock.lock();
        try {
            this.site = "BeiJing";
            siteCondition.signal();
        }finally {
            lock.unlock();
        }
    }

    /*當快遞的里程數大於100時更新數據庫*/
    public void waitKm(){
        lock.lock();
        try {
            while(this.km<=100) {
                try {
                    kmCondition.await();
                    System.out.println("check km thread["+Thread.currentThread().getId()
                            +"] is be notifed.");
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }finally {
            lock.unlock();
        }

        System.out.println("the Km is "+this.km+",I will change db");
    }

    /*當快遞到達目的地時通知用戶*/
    public void waitSite(){
        lock.lock();
        try {
            while(CITY.equals(this.site)) {
                try {
                    siteCondition.await();
                    System.out.println("check site thread["+Thread.currentThread().getId()
                            +"] is be notifed.");
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }finally {
            lock.unlock();
        }
        System.out.println("the site is "+this.site+",I will call user");
    }
}

運行結果:

check km thread[11] is be notifed.
the Km is 101,I will change db
check site thread[15] is be notifed.
the site is BeiJing,I will call user
check site thread[16] is be notifed.
the site is BeiJing,I will call user
check km thread[12] is be notifed.
the Km is 101,I will change db

根據結果可知,Condition可以單獨喚醒某一個或一類的線程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章