Java structured lock vs unstructured lock
Posted huangzifu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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; @Override public 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,谁能看出来)结合这个例子,两句话基本能解释
wait()
tells the calling thread to give up the monitor and go to sleep until some other thread enters the same monitor and calls notify( ).notify()
wakes up the first thread that calledwait()
on the same object.
这种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. */ @Override boolean 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(); @Override boolean 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!高下立判
以上是关于Java structured lock vs unstructured lock的主要内容,如果未能解决你的问题,请参考以下文章
Java 并发 -- lock vs synchronizedvolatile(保证可见性和有序性)悲观锁 vs 乐观锁
structure vs class in swift language