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分為 公平鎖
以物件的方式來操作物件鎖,相對於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);
}