java高並發編程(三)

來源:互聯網
上載者:User

標籤:lam   指定   對比   自己   手工   應該   read   clock   非公平鎖   

java高並發主要有三塊知識點:synchronizer:同步器,在多個線程之間互相之間怎麼進行通訊,同步等;同步容器:jdk提供了同步性的容器,比如concurrentMap,concurrentList,BlockQueen等;ThreadPool:線程池,executor,java在前兩個的基礎之上提供的線程池,很多實際中的問題可以著手解決了。 一、ReentrantLock              jdk裡面提供了一個新的鎖,是手工鎖,它是用來替代synchronized的,叫ReentrantLock,重入鎖,其實synchronized也是可重新進入的,但是這把鎖是和synchronized是有區別的,ReentrantLock是用新的同步方法寫的時候經常用的一個工具;複習之前講的synchronized同步:
/** * reentrantlock用於替代synchronized * 本例中由於m1鎖定this,只有m1執行完畢的時候,m2才能執行 * 這裡是複習synchronized最原始的語義 * @author mashibing */package yxxy.c_020;import java.util.concurrent.TimeUnit;public class ReentrantLock1 {    synchronized void m1() {        for(int i=0; i<10; i++) {            try {                TimeUnit.SECONDS.sleep(1);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(i);        }            }        synchronized void m2() {        System.out.println("m2 ...");    }        public static void main(String[] args) {        ReentrantLock1 rl = new ReentrantLock1();        new Thread(rl::m1).start();        try {            TimeUnit.SECONDS.sleep(1);        } catch (InterruptedException e) {            e.printStackTrace();        }        new Thread(rl::m2).start();    }}
View Code

 

二、使用ReentrantLock完成同樣功能      

/** * reentrantlock用於替代synchronized * 使用reentrantlock可以完成同樣的功能 * 需要注意的是,必須要必須要必須要手動釋放鎖(重要的事情說三遍) * 使用syn鎖定的話如果遇到異常,jvm會自動釋放鎖,但是lock必須手動釋放鎖,因此經常在finally中進行鎖的釋放 * @author mashibing */package yxxy.c_020;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ReentrantLock2 {    Lock lock = new ReentrantLock();    void m1() {        try {            lock.lock(); //synchronized(this)            for (int i = 0; i < 10; i++) {                TimeUnit.SECONDS.sleep(1);                System.out.println(i);            }        } catch (InterruptedException e) {            e.printStackTrace();        } finally {            lock.unlock();        }    }    void m2() {        lock.lock();        System.out.println("m2 ...");        lock.unlock();    }    public static void main(String[] args) {        ReentrantLock2 rl = new ReentrantLock2();        new Thread(rl::m1).start();        try {            TimeUnit.SECONDS.sleep(1);        } catch (InterruptedException e) {            e.printStackTrace();        }        new Thread(rl::m2).start();    }}

三、RenntrantLock的tryLock:          

/** * 使用reentrantlock可以進行“嘗試鎖定”tryLock,這樣無法鎖定,或者在指定時間內無法鎖定,線程可以決定是否繼續等待 * @author mashibing */package yxxy.c_020;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ReentrantLock3 {    Lock lock = new ReentrantLock();    void m1() {        try {            lock.lock();            for (int i = 0; i < 10; i++) {                TimeUnit.SECONDS.sleep(1);                System.out.println(i);            }        } catch (InterruptedException e) {            e.printStackTrace();        } finally {            lock.unlock();        }    }    /**     * 使用tryLock進行嘗試鎖定,不管鎖定與否,方法都將繼續執行     * 可以根據tryLock的傳回值來判定是否鎖定     * 也可以指定tryLock的時間,由於tryLock(time)拋出異常,所以要注意unclock的處理,必須放到finally中     */    void m2() {        /*        boolean locked = lock.tryLock();        System.out.println("m2 ..." + locked);        if(locked) lock.unlock();        */                boolean locked = false;                try {            locked = lock.tryLock(5, TimeUnit.SECONDS);            System.out.println("m2 ..." + locked);        } catch (InterruptedException e) {            e.printStackTrace();        } finally {            if(locked) lock.unlock();        }            }    public static void main(String[] args) {        ReentrantLock3 rl = new ReentrantLock3();        new Thread(rl::m1).start();        try {            TimeUnit.SECONDS.sleep(1);        } catch (InterruptedException e) {            e.printStackTrace();        }        new Thread(rl::m2).start();    }}
View Code

console:

012345m2 ...false6789
View Code

 

四、ReentrantLock的lockInterruptibly方法:    

/** * 使用ReentrantLock還可以調用lockInterruptibly方法,可以對線程interrupt方法做出響應, * 在一個線程等待鎖的過程中,可以被打斷 *  * @author mashibing */package yxxy.c_020;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;import java.util.function.Function;public class ReentrantLock4 {            public static void main(String[] args) {        Lock lock = new ReentrantLock();                        Thread t1 = new Thread(()->{            try {                lock.lock();                System.out.println("t1 start");                TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);                System.out.println("t1 end");            } catch (InterruptedException e) {                System.out.println("interrupted!");            } finally {                lock.unlock();            }        });        t1.start();                Thread t2 = new Thread(()->{            try {                //lock.lock();                lock.lockInterruptibly(); //可以對interrupt()方法做出響應                System.out.println("t2 start");            } catch (InterruptedException e) {                System.out.println("interrupted!");            } finally {                lock.unlock();            }        });        t2.start();                try {            TimeUnit.SECONDS.sleep(1);        } catch (InterruptedException e) {            e.printStackTrace();        }        t2.interrupt(); //打斷線程2的等待            }}

console:

t1 startinterrupted!Exception in thread "Thread-1" java.lang.IllegalMonitorStateException    at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)    at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)    at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)    at yxxy.c_020.ReentrantLock4.lambda$1(ReentrantLock4.java:42)    at java.lang.Thread.run(Thread.java:745)

t1線程牢牢的拿到鎖之後,一直sleep不會釋放,如果t2線程中的run方法使用lock.lock(),那麼t2線程就會一直傻傻的等著這把鎖,不能被其他線程打斷;

而使用lockInterruptibly()方法是可以被打斷的,主線程main調用t2.interrupt()來打斷t2,告訴他是不會拿到這把鎖的,別等了;

報錯是因為lock.unlock()這個方法報錯的,因為都沒有拿到鎖,無法unlock();是代碼的問題,應該判斷有鎖,已經鎖定的情況下才lock.unlock();

 

五、ReentrantLock還可以指定為公平鎖            

預設的synchronized全都是不公平鎖;

什麼是公平鎖,什麼是不公平鎖,假設很多個線程訪問同一份資源的時候都要鎖定,其中某一個線程A如果拿到了,他佔有這把鎖之後,其他人是都訪問不了的,都得在那等著;什麼時候一旦線程A釋放了這把鎖,那麼剩下的線程中哪個線程得到這把鎖,這事說不定,這個要看線程調度器自己去選哪個了,所以這叫競爭鎖;也就是說等待的線程裡面是沒有公平性可言的;不過這種效率比較高,線程調度器不用計算到底哪個線程等的時間更長,所以預設的synchronized是非公平鎖; 公平鎖就是,誰等的時間長讓誰得到那把鎖。 
/** * ReentrantLock還可以指定為公平鎖 *  * @author mashibing */package yxxy.c_020;import java.util.concurrent.locks.ReentrantLock;public class ReentrantLock5 extends Thread {            private static ReentrantLock lock = new ReentrantLock(); //參數為true表示為公平鎖,請對比輸出結果        public void run() {        for(int i=0; i<100; i++) {            lock.lock();            try{                System.out.println(Thread.currentThread().getName()+"獲得鎖");            }finally{                lock.unlock();            }        }    }    public static void main(String[] args) {        ReentrantLock5 rl=new ReentrantLock5();        Thread th1=new Thread(rl);        Thread th2=new Thread(rl);        th1.start();        th2.start();    }}

 

 

六、

 

                

java高並發編程(三)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.