不可重入锁
先来设计一种锁,这一种锁其实是不可重入锁
package 可重入锁和不可重入锁;
public class LockDemo {
private boolean isLock = false;
public synchronized void lock() {
if(isLock){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
isLock = true;
}
public synchronized void unLock() {
isLock = false;
notify();
}
}
package 可重入锁和不可重入锁;
public class TextDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Demo demo = new Demo();
demo.printf();
}
}
package 可重入锁和不可重入锁;
public class Demo {
LockDemo lock = new LockDemo();
public void printf() {
lock.lock();
System.out.println("炒饭");
addSomeThing();
lock.unLock();
}
public void addSomeThing() {
lock.lock();
System.out.println("突然加入某些东西");
lock.unLock();
}
}
当调用print()方法时,获得了锁,这时就无法再调用doAdd()方法,这时必须先释放锁才能调用,所以称这种锁为不可重入锁,也叫自旋锁。(如上方法出现了死锁问题)
可重入锁
设计如下:
public class Lock{
boolean isLocked = false;
Thread lockedBy = null;
int lockedCount = 0;
public synchronized void lock()
throws InterruptedException{
Thread thread = Thread.currentThread();
while(isLocked && lockedBy != thread){
wait();
}
isLocked = true;
lockedCount++;
lockedBy = thread;
}
public synchronized void unlock(){
if(Thread.currentThread() == this.lockedBy){
lockedCount--;
if(lockedCount == 0){
isLocked = false;
notify();
}
}
}
相对来说,可重入就意味着:线程可以进入任何一个它已经拥有的锁所同步着的代码块。
第一个线程执行print()方法,得到了锁,使lockedBy等于当前线程,也就是说,执行的这个方法的线程获得了这个锁,执行addSomeThing()方法时,同样要先获得锁,因不满足while循环的条件,也就是不等待,继续进行,将此时的lockedCount变量,也就是当前获得锁的数量加一,当释放了所有的锁,才执行notify()。如果在执行这个方法时,有第二个线程想要执行这个方法,因为lockedBy不等于第二个线程,导致这个线程进入了循环,也就是等待,不断执行wait()方法。只有当第一个线程释放了所有的锁,执行了notify()方法,第二个线程才得以跳出循环,继续执行。
这就是可重入锁的特点。