多線程高級講解五: 多線程的Lock鎖,多線程同步、多線程併發的概念

 

同步 和 併發 : 對於程序員來說,他們其實是有兩個意思的,一個是多線程層面,一個是網站請求服務器層面。

 

對於網站的請求層面來說:

同步:就是代碼一步一步的有順序的向下執行。

併發:就是多個請求同時訪問一臺服務器。

對於多線程層面來說:

同步: 就是加鎖,爲了保證數據的原子性。也就是保證數據的正確性。

併發:就是多個線程,操作同一個共享的資源。

 

所以:他們之前是有區別的,不是一個概念。

 

接下來就說說Lock鎖,他是jdk1.5提供併發包的一個工具。以前沒有Lock鎖的時候,大家都是用synchronized做鎖。那爲什麼用Lock做鎖呢 ?換句話說:就是Lock鎖與synchronized的區別是什麼 ?

用過synchronized的人都知道,synchronized(){} 這後面的{}就是需要被鎖住的代碼。他這個是自動的將包裹的代碼全部上鎖,執行到最後一個花括號就自動解鎖。

而Lock鎖,是手動上鎖,手動解鎖,相對來說更加靈活。而且效率也比synchronized的效率高,jdk1.5專門爲多線程開發工具包,處理了很多效率問題,所以推薦使用。

區別:

1. Lock鎖,可以嘗試非阻塞式的獲取鎖,當線程獲取到鎖之後,就會持有鎖,只要程序沒有手動的釋放鎖,那麼這個鎖是絕對不會被釋放的。還可以在任意位置,手動的釋放鎖。還可以指定時間範圍內獲取到鎖,如果指定時間範圍內,依然沒有獲取到鎖,則返回,重新開始。所以Lock鎖是相當靈活的。

2. synchronized是屬於代碼塊,當代碼執行完畢之後,或者中間出現異常,就會自動的釋放鎖資源,功能比較單一,且效率沒有Lock鎖高。

 

 

接下來,就用一下Lock做鎖,並實現一下在使用Lock鎖的情況下,怎麼來完成線程之前的通訊。  

public class Person {

    public String username;
    public int age;

    /**
     * true 生產者線程等待,   false 消費者線程等待
     */
    public boolean flag = false;

    /**
     * 重入鎖
     */
    public Lock lock = new ReentrantLock();
}






public class WriteThread extends Thread {

    private Person person;
    public Condition condition;

    public WriteThread(Person person, Condition condition) {
        this.person = person;
        this.condition = condition;
    }

    @Override
    public void run() {

        /**
         * 定義一個局部變量。
         * 當這個值爲偶數時,爲Person類賦值: 偶數   0
         * 當這個數爲奇數時,爲Person類賦值: 奇數   1
         */
        int data = 0;

        while (true) {

            try {
                //開啓鎖,注意這個鎖的位置,一定要在上面。
                person.lock.lock();

                /**
                 * true: 等待消費
                 */
                if (person.flag) {
                    // await 用Lock鎖的線程通訊
                    condition.await();
                }


                if (data == 0) {
                    person.username = "偶數";
                    person.age = 0;
                } else {
                    person.username = "奇數";
                    person.age = 1;
                }

                /**
                 * 依次改變data的值爲: 偶數、奇數
                 */
                data = (data + 1) % 2;
                person.flag = false;

                // signal 用Lock鎖的線程通訊
                condition.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                /**
                 * 在finally中解鎖。
                 */
                person.lock.unlock();
            }
        }

    }
}





public class ReadThread extends Thread {

    public Person person;
    public Condition condition;

    public ReadThread(Person person, Condition condition) {
        this.person = person;
        this.condition = condition;
    }

    @Override
    public void run() {

        while (true) {
            try {

                /**
                 * 上鎖:
                 * 使用Lock鎖之後,有個缺點,就是說,如果代碼中間出現異常,如果沒有特殊處理,下面的鎖就一定不會解鎖了。
                 * 那麼處理這個問題也很簡單,用try catch的finally。
                 *
                 * 注意這個鎖的位置,一定要在上面。
                 */
                person.lock.lock();

                if (!person.flag) {
                    condition.await();
                }

                System.out.println(person.username + "," + person.age);
                person.flag = true;
                condition.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                /**
                 * 在finally中解鎖。
                 */
                person.lock.unlock();
            }
        }
    }
}



public class Test {

    public static void main(String[] args) {

        Person person = new Person();
        /**
         * 使用Lock鎖後,線程之前通訊的方式用Condition類。
         * Condition底層原理也是 使用wait 和 notify,不過調用的方法改了。
         */
        Condition condition = person.lock.newCondition();

        WriteThread writeThread = new WriteThread(person, condition);
        ReadThread readThread = new ReadThread(person, condition);

        writeThread.start();
        readThread.start();
    }
}

 

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