什么是可重入性:线程可以进入任何一个他已经拥有锁的对象所锁住的代码块。
先举个例子看看普通锁:
public class unReentrantLock {
private boolean isLock=false;//标志是否加锁
public synchronized void lock() throws InterruptedException{
/*
isLock为true的话,说明这个对象已经被锁住了,这个时候执行while内的方法,通过调用
wait方法让调用该方法的线程进入等待队列。
至于用while,不用if,是防止虚假唤醒
虚假唤醒:obj.wait()除了在obj.notify()和obj.notifyAll()以外,还会在其他某些情况下被唤醒,而这个时候不应该被唤醒。
用while后就能反复检查进入的临界条件是否满足
*/
while(isLock){
wait();
}
isLock=true;//如果对象没有被锁住,才会执行到这,这时致它为true,相当于是这个对象被加锁。
}
public synchronized void unlock(){
isLock=false;//使他为false,相当于解锁。这个线程放开了对这个对象的拥有权
notify();//通知等待队列中的某个线程出队。
}
}
public class unReentrant {
private unReentrantLock lock = new unReentrantLock();
private int count = 0;
public void lockA() throws InterruptedException {
lock.lock();//锁住lock对象,当其他线程执行到这,因为无法获得lock对象的锁,就会阻塞,就无法对下面的临界区进行操作
/**
*这个操作是分步进行的,先取count的值,再加一,如果不加锁,多个线程同时进行,结果就会超过预计,所以加锁,
* 保证只有一个线程访问他。
*/
this.count++;
lock.unlock();//执行结束后释放锁
}
public void lockB() throws InterruptedException {
lock.lock();//例如线程A锁住lock对象,islock被致为true
/**
* 到这里线程A想调用lockA方法,但是islock已经为true,因为线程A自己已经锁住这个对象一次了,
* 所以线程A也无法进入临界区。如果用过synchronized,会发现他没有这个问题,因为他是可重入锁
*/
lockA();
lock.unlock();
}
}
普通的锁无法使同一线程多次访问被锁住的对象,所以这里引入可重入锁。
接着看例子:
public class ReentrantLock {
private boolean isLock = false;//标志是否加锁
Thread isCurrentThread = null;//用来判断是否是当前线程访问锁对象
int lockCount = 0;//用来统计同一个线程重复对一个锁对象加锁的次数
public synchronized void lock() throws InterruptedException {
Thread currentThread = Thread.currentThread();//获取当前线程
/**
* 除了isLock为true,即这个对象被锁住外,还需要同时满足这个这个线程不是当前线程,
* 所以如果是当前线程再次访问这个锁对象时,虽然islock为true,但是第二个条件不满足,
* 依旧while中语句。
*/
while (isLock && isCurrentThread != currentThread) {
wait();
}
isLock = true;//设置isLock为true,相当于进行加锁
isCurrentThread = currentThread;//将IsCurrentThread至为当前线程
lockCount++;//当前线程对该锁对象加锁的数量加1;
}
public synchronized void unlock() {
if (Thread.currentThread() == this.isCurrentThread) {//如果调用该方法的线程是当前线程
lockCount--;//数量减一
if (lockCount == 0) {//如果加在当前线程上的锁减到0
isLock = false;//使他为false,相当于解锁。这个线程放开了对这个对象的拥有权
notify();//通知等待队列中的某个线程出队。
}
}
}
}
java当中的synchroized和java.util.concurrent.locks.ReentrantLock都是可重入锁