Java structured lock vs unstructured lock
标签:stscalling内存removecalhead代码err方法
什么是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,谁能看出来)结合这个例子,两句话基本能解释
这种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语句!!!