java 安全執行緒 Lock

來源:互聯網
上載者:User

標籤:java

對於安全執行緒我們前面使用了synchronized關鍵字,對於線程的協作我們使用Object.wait()和Object.notify()。在JDK1.5中java為我們提供了Lock來實現與它們相同的功能,並且效能優於它們,在JDK1.6時,JDK對synchronized做了最佳化,在效能上兩種方式差距不大了。

一、為什麼出現lock

  synchronized修飾的代碼塊,當一個線程擷取了對應的鎖,並執行該代碼塊時,其他線程便只能一直等待,等待擷取鎖的線程釋放鎖,如果沒有釋放則需要無限的等待下去。擷取鎖的線程釋放鎖只會有兩種情況:

  1、擷取鎖的線程執行完了該代碼塊,然後線程釋放對鎖的佔有。

  2、線程執行發生異常,此時JVM會讓線程自動釋放鎖。

Lock與synchronized對比:

  1、Lock不是Java語言內建的,synchronized是Java語言的關鍵字,因此是內建特性。Lock是一個類,通過這個類可以實現同步訪問。

  2、synchronized不需要手動釋放鎖,當synchronized方法或者synchronized代碼塊執行完之後,系統會自動讓線程釋放對鎖的佔用;而Lock則必須要使用者去手動釋放鎖,如果沒有主動釋放鎖,就有可能導致出現死結現象。

二、java.util.concurrent.locks包中常用的類和介面。

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

public interface Lock {    //用來擷取鎖。如果鎖已被其他線程擷取,則進行等待。    void lock();   // 當通過這個方法去擷取鎖時,如果線程正在等待擷取鎖,則這個線程能夠響應中斷,即中斷線程的等待狀態    void lockInterruptibly() throws InterruptedException;    //它表示用來嘗試擷取鎖,如果擷取成功,則返回true,如果擷取失敗(即鎖已被其他線程擷取),則返回false    boolean tryLock();    //與tryLock()方法是類似的,只不過區別在於這個方法在拿不到鎖時會等待一定的時間,在時間期限之內如果還拿不到鎖,就返回false。如果如果一開始拿到鎖或者在等待期間內拿到了鎖,則返回true。    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;    //釋放鎖    void unlock();    Condition newCondition();}

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

1、Lock與unlock
  Lock用於擷取鎖,但它不會主動釋放鎖所以需要與unlock()配合使用。一般在使用Lock時必須在try{}catch{}塊中進行,並且將釋放鎖的操作放在finally塊中進行,以保證鎖一定被被釋放,防止死結的發生。

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

package com.jalja.base.threadTest;import java.util.concurrent.locks.ReentrantLock;public class LockTest implements Runnable{    public static ReentrantLock lock=new ReentrantLock();    public static int c=0;    public void run() {        for(int i=0;i<1000;i++){            lock.lock();//擷取鎖            try {                System.out.println(Thread.currentThread().getName()+"獲得鎖");                System.out.println(Thread.currentThread().getName()+"====>"+c);                c++;            } catch (Exception e) {                e.printStackTrace();            }finally{                System.out.println(Thread.currentThread().getName()+"釋放鎖");                lock.unlock();//釋放鎖            }        }    }    public static void main(String[] args) {        LockTest lt=new LockTest();        Thread thread1=new Thread(lt);        Thread thread2=new Thread(lt);        thread1.start();        thread2.start();        try {            thread1.join();            thread2.join();        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println(c);    }}

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

注意:同一個線程可以連續獲得同一把鎖,但也必須釋放相同次數的鎖。允許下面的寫法

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

          lock.lock();//擷取鎖            lock.lock();            lock.lock();            try {                System.out.println(Thread.currentThread().getName()+"獲得鎖");                System.out.println(Thread.currentThread().getName()+"====>"+c);                c++;            } catch (Exception e) {                e.printStackTrace();            }finally{                System.out.println(Thread.currentThread().getName()+"釋放鎖");                lock.unlock();//釋放鎖                lock.unlock();//釋放鎖                lock.unlock();//釋放鎖            }

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

2、擷取鎖等待時間tryLock(long time, TimeUnit unit)
  如果你約朋友打籃球,約定時間到了你朋友還沒有出現,你等1小時後還是沒到,我想你肯定會掃興的離去。對於線程來說也應該時這樣的,因為通常我們是無法判斷一個線程為什麼會無法獲得鎖,但我們可以給該線程一個擷取鎖的時間限制,如果到時間還沒有擷取到鎖,則放棄擷取鎖。

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

package com.jalja.base.threadTest;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.ReentrantLock;public class TryLockTest implements Runnable{    public static ReentrantLock lock=new ReentrantLock();    private static int m=0;    public void run() {        try {            if(lock.tryLock(1, TimeUnit.SECONDS)){//設定擷取鎖的等待時間長度1秒                System.out.println(Thread.currentThread().getName()+"獲得鎖");                m++;                //Thread.sleep(2000);//設定休眠2秒            }else{                System.out.println(Thread.currentThread().getName()+"未獲得鎖");            }        } catch (Exception e) {            e.printStackTrace();        }finally{            if(lock.isHeldByCurrentThread()){                lock.unlock();            }        }    }    public static void main(String[] args) {        TryLockTest thread1=new TryLockTest();        TryLockTest thread2=new TryLockTest();        Thread th1=new Thread(thread1);        Thread th2=new Thread(thread2);        th1.start();        th2.start();        try {            //讓main線程等待th1、th2線程執行完畢後,再繼續執行            th1.join();            th2.join();        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println(m);    }}

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

執行結果:

Thread-0獲得鎖Thread-1獲得鎖2

  該代碼就是讓線程在鎖請求中,最多等待1秒,如果超過一秒沒有獲得鎖就返回false,如果獲得了鎖就返回true,根據執行結果可以看出Thread-1線程在1秒內獲得了鎖。

我們開啟注釋 //Thread.sleep(2000);就會發現Thread-1或Thread-0一定會有一個是未獲得鎖,這是因為佔用鎖的線程時間是2秒,而等待鎖的線程等待時間是1秒,所以在1秒後的瞬間它就放棄了請求鎖操作。


java 安全執行緒 Lock

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.