1. 程式人生 > >synchronized和ReentrantLock區別

synchronized和ReentrantLock區別

sychronized

在java中,每一個物件有且僅有一個同步鎖。這也意味著,同步鎖是依賴於物件而存在。
當我們呼叫某物件的synchronized方法時,就獲取了該物件的同步鎖。例如,synchronized(obj)就獲取了“obj這個物件”的同步鎖。
不同執行緒對同步鎖的訪問是互斥的。也就是說,某時間點,物件的同步鎖只能被一個執行緒獲取到!通過同步鎖,我們就能在多執行緒中,實現對“物件/方法”的互斥訪問。 例如,現在有兩個執行緒A和執行緒B,它們都會訪問“物件obj的同步鎖”。假設,在某一時刻,執行緒A獲取到“obj的同步鎖”並在執行一些操作;而此時,執行緒B也企圖獲取“obj的同步鎖” —— 執行緒B會獲取失敗,它必須等待,直到執行緒A釋放了“該物件的同步鎖”之後執行緒B才能獲取到“obj的同步鎖”從而才可以執行。

sychronized有三條原則:
1. 當一個執行緒訪問“某物件”的“synchronized方法”或者“synchronized程式碼塊”時,其他執行緒對“該物件”的該“synchronized方法”或者“synchronized程式碼塊”的訪問將被阻塞。
2. 當一個執行緒訪問“某物件”的“synchronized方法”或者“synchronized程式碼塊”時,其他執行緒仍然可以訪問“該物件”的非同步程式碼塊。
3. 當一個執行緒訪問“某物件”的“synchronized方法”或者“synchronized程式碼塊”時,其他執行緒對“該物件”的其他的“synchronized方法”或者“synchronized程式碼塊”的訪問將被阻塞。

synchronized會在進入同步塊的前後分別形成monitorenter和monitorexit位元組碼指令.在執行monitorenter指令時會嘗試獲取物件的鎖,如果此沒物件沒有被鎖,或者此物件已經被當前執行緒鎖住,那麼鎖的計數器加一,每當monitorexit被鎖的物件的計數器減一.直到為0就釋放該物件的鎖.由此synchronized是可重入的,不會出現自己把自己鎖死.

ReentrantLock

ReentrantLock是一個可重入的互斥鎖,又被稱為“獨佔鎖”

顧名思義,ReentrantLock鎖在同一個時間點只能被一個執行緒鎖持有;而可重入的意思是,ReentrantLock鎖,可以被單個執行緒多次獲取。
ReentrantLock分為 公平鎖

非公平鎖 。它們的區別體現在獲取鎖的機制上是否公平。 是為了保護競爭資源,防止多個執行緒同時操作執行緒而出錯,ReentrantLock在同一個時間點只能被一個執行緒獲取(當某執行緒獲取到“鎖”時,其它執行緒就必須等待);ReentraantLock是通過一個FIFO的等待佇列來管理獲取該鎖所有執行緒的。在“公平鎖”的機制下,執行緒依次排隊獲取鎖;而“非公平鎖”在鎖是可獲取狀態時,不管自己是不是在佇列的開頭都會獲取鎖。
以物件的方式來操作物件鎖,相對於sychronized需要在finally中去釋放鎖。

synchronized和ReentrantLock的區別

除了synchronized的功能,多了三個高階功能。
等待可中斷,公平鎖,繫結多個Condition。
1. 等待可中斷:在持有鎖的執行緒長時間不釋放鎖的時候,等待的執行緒可以選擇放棄等待,tryLock(long timeout, TimeUnit unit)
2. 公平鎖:按照申請鎖的順序來一次獲得鎖稱為公平鎖,synchronized的是非公平鎖,ReentrantLock可以通過建構函式實現公平鎖。new RenentrantLock(boolean fair)
3. 繫結多個Condition:通過多次newCondition可以獲得多個Condition物件,可以簡單的實現比較負責的執行緒同步的功能,通過await(),signal();

實現消費者模式

sychronized

 public static class Depot {
        private int mCapacity;
        private int mSize;

        public Depot(int capacity) {

            mCapacity = capacity;
            mSize = 0;
        }


        public synchronized void produce(int val) {
            try {
                int left = val;
                while (left > 0) {
                    while (mSize >= mCapacity)
                        wait();

                    int inc = (mSize + left) > mCapacity ? (mCapacity - mSize) : left;
                    mSize += inc;
                    left -= inc;

                    System.out.println("produce  Thread: " + Thread.currentThread().getName() + " val: " + val + " mSize: " + mSize + " left: " + left);

                    notifyAll();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public synchronized void consume(int val) {
            try {
                int left = val;
                while (left > 0) {
                    while (mSize <= 0)
                        wait();
                    int inc = (mSize - left) < 0 ? mSize : left;
                    mSize -= inc;
                    left -= inc;
                    System.out.println("consume  Thread: " + Thread.currentThread().getName() + " val: " + val + " mSize: " + mSize + " left: " + left);
                    notifyAll();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private static class Producer {
        private Depot depot;

        public Producer(Depot depot) {
            this.depot = depot;
        }

        public void produce(int val) {
            new Thread() {
                @Override
                public void run() {
                    depot.produce(val);
                }
            }.start();
        }
    }



    static class Customer {
        private Depot depot;

        public Customer(Depot depot) {
            this.depot = depot;
        }

        public void consume(int val) {
            new Thread() {
                @Override
                public void run() {
                    depot.consume(val);
                }
            }.start();
        }
    }


    public static void main(String[] args) {
        Depot depot = new Depot(100);
        Producer producer = new Producer(depot);
        Customer customer = new Customer(depot);

        producer.produce(60);
        producer.produce(120);
        customer.consume(90);
        customer.consume(150);
        producer.produce(110);
    }

ReentrantLock

public static class Depot {
        private int mCapacity;
        private int mSize;
        private Lock mLock;
        private Condition mFullCondition;
        private Condition mEmptyCondition;

        public Depot(int capacity) {
            mCapacity = capacity;
            mSize = 0;
            mLock = new ReentrantLock();
            mFullCondition = mLock.newCondition();
            mEmptyCondition = mLock.newCondition();
        }


        public void produce(int val) {
            mLock.lock();
            try {
                int left = val;
                while (left > 0) {
                    while (mSize >= mCapacity)
                        mFullCondition.await();

                    int inc = (mSize + left) > mCapacity ? (mCapacity - mSize) : left;
                    mSize += inc;
                    left -= inc;

                    System.out.println("produce  Thread: " + Thread.currentThread().getName() + " mSize: " + mSize + " left: " + left);

                    mEmptyCondition.signal();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                mLock.unlock();
            }
        }

        public void consume(int val) {
            mLock.lock();

            try {
                int left = val;
                while (left > 0) {
                    while (mSize <= 0)
                        mEmptyCondition.await();
                    int inc = (mSize - left) < 0 ? mSize : left;
                    mSize -= inc;
                    left -= inc;
                    System.out.println("consume  Thread: " + Thread.currentThread().getName() + " mSize: " + mSize + " left: " + left);
                    mFullCondition.signal();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                mLock.unlock();
            }
        }
    }

    static class Producer {
        private Depot depot;

        public Producer(Depot depot) {
            this.depot = depot;
        }

        public void produce(int val) {
            new Thread() {
                @Override
                public void run() {
                    depot.produce(val);
                }
            }.start();
        }
    }

    static class Customer {
        private Depot depot;

        public Customer(Depot depot) {
            this.depot = depot;
        }

        public void consume(int val) {
            new Thread() {
                @Override
                public void run() {
                    depot.consume(val);
                }
            }.start();
        }
    }


    public static void main(String[] args) {
        Depot depot = new Depot(100);
        Producer producer = new Producer(depot);
        Customer customer = new Customer(depot);

        producer.produce(60);
        producer.produce(120);
        customer.consume(90);
        customer.consume(150);
        producer.produce(110);
    }