Java structured lock vs unstructured lock
什么是structured lock?先來段代碼:
public synchronized boolean contains(final Integer object) {Entry pred = this.head;Entry curr = pred.next;while (curr.object.compareTo(object) < 0) {pred = curr;curr = curr.next;}return object.equals(curr.object);}這段代碼用synchronized來解決并發問題,這個例子是在方法上上鎖,也就是object級別,那么一旦這個object被上鎖,該object的所有同步方法都會被鎖,鎖被釋放的時機是方法執行完畢,提到synchronized,也順便提一下wait/notify好了,看以下代碼:
public class Main {public static void main(String[] args){ThreadB b = new ThreadB();b.start();synchronized(b){try{System.out.println("Waiting for b to complete...");b.wait();}catch(InterruptedException e){e.printStackTrace();}System.out.println("Total is: " + b.total);}} }class ThreadB extends Thread{int total;@Overridepublic void run(){synchronized(this){try {sleep(2000);} catch (InterruptedException e) {System.out.println("wokao");}for(int i=0; i<100 ; i++){total += i;}notify();}} }(這個程序一般運行不會有問題,但有個潛在的bug,誰能看出來)結合這個例子,兩句話基本能解釋
這種synchronized對同步機制,又稱為structured lock,因為看起來很結構化,很規整有沒有?
但是結果化對應對結果就是不夠靈活。什么時候需要靈活呢?舉個例子
有這么個鏈表A->B->C->D->E->F
假設有如下一組工作:
1.寫A和B;
2.寫B和C
3.寫C和D
4.寫D和E
5.寫E和F
如果用synchronized把1中的A和B鎖了,那么2就必須等A和B都執行完成才能,執行,但是有必要嗎?其實只要等A結束,2就應該可以執行了,依次往下,這就是所謂的hand in hand locking,
就是連環鎖,描述如下:
lock A and B, start job 1
unlock A, lock C, start job 2
unlock B, lock D, start job 3 ...
這種連環鎖,顯然synchronized是做不到的,sychronized里面可以套其他的synchronized,那只能形成一個nested結構。
這就是synchronized或者說structured lock的局限性。
那么這種情況下 unstructured lock就有用了,看一個使用的例子:
public static final class CoarseList extends ListSet {/** TODO Declare a lock for this class to be used in implementing the* concurrent add, remove, and contains methods below.*/ReentrantLock lk= new ReentrantLock();/*** Default constructor.*/public CoarseList() {super();}/*** {@inheritDoc}** TODO Use a lock to protect against concurrent access.*/@Overrideboolean add(final Integer object) {try{lk.lock();Entry pred = this.head;Entry curr = pred.next;while (curr.object.compareTo(object) < 0) {pred = curr;curr = curr.next;}if (object.equals(curr.object)) {return false;} else {final Entry entry = new Entry(object);entry.next = curr;pred.next = entry;return true;}}finally {lk.unlock();}}
這里的ReentrantLock就很靈活,不過必須顯式地unlock,否則會出問題(就像c++必須顯示delete內存一樣),為了防止意外例如拋出exception,應該把unlock語句放在finally里,所以這里的弊端想必也能看到了吧,到處都要寫try finally語句!!!
unstructured lock還有個好處可以區分讀寫鎖,理論上多個線程讀不會有問題,所以用一個比較弱的讀寫鎖即可,而一旦有一個線程寫,其他線程就要注意了,最多只能有一個線程在被鎖對象上寫,此時其他的線程無論讀還是寫,都得等。上例子:
public static final class RWCoarseList extends ListSet {/** TODO Declare a read-write lock for this class to be used in* implementing the concurrent add, remove, and contains methods below.*//*** Default constructor.*/public RWCoarseList() {super();}/*** {@inheritDoc}** TODO Use a read-write lock to protect against concurrent access.*/ReentrantReadWriteLock rwlk = new ReentrantReadWriteLock();@Overrideboolean add(final Integer object) {try {rwlk.writeLock().lock();Entry pred = this.head;Entry curr = pred.next;while (curr.object.compareTo(object) < 0) {pred = curr;curr = curr.next;}if (object.equals(curr.object)) {return false;} else {final Entry entry = new Entry(object);entry.next = curr;pred.next = entry;return true;}}finally {rwlk.writeLock().unlock();}}
?
還沒完,unstructured lock的第三個好處是,支持trylock,看名字就可以看出來,就是先嘗試拿鎖,拿不到,做其他事去。想想synchronized是怎么做的,先嘗試拿鎖,拿不到,block!高下立判
?
轉載于:https://www.cnblogs.com/huangzifu/p/7680196.html
總結
以上是生活随笔為你收集整理的Java structured lock vs unstructured lock的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ACM 2017 ACM-ICPC 亚洲
- 下一篇: Eclipse Collections随