JAVA多線程-Lock類API

Lock的api的用法:

我們先看下lock接口中有哪些方法:

public interface Lock {

    /**

     * 獲取鎖,如果獲取不到就一直等待,與synchronized一樣
      */

    void lock();


    /**
    * 該方法比較特殊,當通過這個方法去獲取鎖時,如果線程正在等待獲取鎖,
    * 則這個線程能夠響應中斷,
    * 即中斷線程的等待狀態。也就是說,
    * 當兩個線程同時通過lock.lockInterruptibly()想獲取某個鎖時,
    * 假若此時線程A獲取到了鎖,而線程B只有在等待,
    * 那麼對線程B調用threadB.interrupt()方法能夠中斷線程B的等待過程。
    */

    void lockInterruptibly() throws InterruptedException;

    /**
     * 該方法是有返回值的,它表示用來嘗試獲取鎖,如果獲取成功,則返回true,
     * 如果獲取失敗(即鎖已被其他線程獲取),則返回false,
     * 也就說這個方法無論如何都會立即返回。在拿不到鎖時不會一直在那等待。     
    */

    boolean tryLock();



    /**

     * 該方法和tryLock()方法是類似的,只不過區別在於這個方法在拿不到鎖時會等待一定的時間,
     * 在時間期限之內如果還拿不到鎖,就返回false。
     * 如果如果一開始拿到鎖或者在等待期間內拿到了鎖,則返回true  
    */

    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;



    /**

     * 釋放鎖

     */

    void unlock();



    /**
     *
     * Condition是Java提供了來實現等待/通知的類,
     * Condition類還提供比wait/notify更豐富的功能,
     * Condition對象是由lock對象所創建的。但是同一個鎖可以創建多個Condition的對象,
     * 即創建多個對象監視器。這樣的好處就是可以指定喚醒線程。
     * notify喚醒的線程是隨機喚醒一個 ,具體得會在後面線程間得通信講    */

    Condition newCondition();

}

ReentrantLock,意思是“可重入鎖”,關於可重入鎖,我們在前面synchronized中已經提到過,ReentrantLock簡單得用法我們前面一篇也簡單得用到過。ReentrantLock是實現了Lock接口的類,並且ReentrantLock提供了更多的方法,我們先看下ReentrantLock類繼承關係:

public class ReentrantLock implements Lock, java.io.Serializable

我們可以看到實現了lock,和序列化接口。

那麼就先使用下lock得api.

Lock()和unlock()我們上一章已經用到過,下面我們講另外得方法:

tryLock()用法:

public class Account {

    private Lock lock = new ReentrantLock();

    public   void add(BigDecimal amount , String name) {

        //嘗試獲取鎖,獲取不到,直接跳出

        if(lock.tryLock()) {

            System.out.println(" 開始充值,線程名: " + Thread.currentThread().getName());

            try {

                Thread.sleep(2000);

                System.out.println(" 結束充值,線程名: " + Thread.currentThread().getName());

            } catch (InterruptedException e) {

                e.printStackTrace();

            }finally {

                lock.unlock();

            }

        }else {

            System.out.println("獲取鎖失敗,不進行充值,線程名: " + Thread.currentThread().getName());

        }

    }

}

然後繼續充值線程類:


public class CzThread extends Thread{


    private Account account;


    private String accountName;

  
    public CzThread(Account account) {

        this.account = account;

    }

   

    @Override

    public void run() {

        account.add(new BigDecimal("100"), accountName);

    }


    public Account getAccount() {

        return account;

    }


    public void setAccount(Account account) {

        this.account = account;

    }


    public String getAccountName() {

        return accountName;

    }


    public void setAccountName(String accountName) {

        this.accountName = accountName;

    }


}

主線程類:

public class MainThread {

    public static void main(String[] args) throws InterruptedException {

        Account account = new Account();

       

        CzThread cz1 = new CzThread(account);

        cz1.setName("thread1");

        cz1.start();

       

        CzThread cz2 = new CzThread(account);

        cz2.setName("thread2");

        cz2.start();

    }

}

 

執行結果:

獲取鎖失敗,不進行充值,線程名: thread2

 開始充值,線程名: thread1

 結束充值,線程名: thread1

 

我們繼續看下tryLock(long time, TimeUnit unit)用法,稍微修改下Account類:

public class Account {

    private Lock lock = new ReentrantLock();

    public   void add(BigDecimal amount , String name) throws InterruptedException {

        /***

         * 等待了5s後

         */

        if(lock.tryLock(5, TimeUnit.SECONDS)) {

            System.out.println(" 開始充值,線程名: " + Thread.currentThread().getName());

            try {

                Thread.sleep(2000);

                System.out.println(" 結束充值,線程名: " + Thread.currentThread().getName());

            } catch (InterruptedException e) {

                e.printStackTrace();

            }finally {

                lock.unlock();

            }

        }else {

            System.out.println("獲取鎖失敗,不進行充值,線程名: " + Thread.currentThread().getName());

        }

    }
   

}

 

充值類也要修改下,因爲需要拋異常:

public class CzThread extends Thread{

    private Account account;

    private String accountName;
   

    public CzThread(Account account) {

        this.account = account;

    }

   
    @Override

    public void run() {

        try {

            account.add(new BigDecimal("100"), accountName);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

    }

    public Account getAccount() {

        return account;

    }

    public void setAccount(Account account) {

        this.account = account;

    }


    public String getAccountName() {

        return accountName;

    }


    public void setAccountName(String accountName) {

        this.accountName = accountName;

    }
}

看下執行結果:

開始充值,線程名: thread2

 結束充值,線程名: thread2

 開始充值,線程名: thread1

 結束充值,線程名: thread1

 

我們看到線程1和2都執行完了,因爲等待了5s得鎖,所以會執行。

lockInterruptibly與Condition,我們會在後面得線程通信講,下一篇我們會解析,我們上面講的得方法得原理。

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