ReentrantLock也是一种可重入锁,类似于synchronized,也就是在拥有锁的情况下可以调用其它需要本锁的方法或者代码块。lock.getHoldCount()可以获得当前线程拥有锁的层数,可以理解为重入了几层。当为0的时候代表当前线程没有占用锁,每重入一次count就加1.
调用其lock()方法会占用锁,调用unlock()会释放锁,但是需要注意必须手动unlock释放锁,否则其他线程会永远阻塞。而且发生异常不会自动释放锁,所以编写程序的时候需要在finally中手动释放锁。**
//普通的加锁解锁过程
public class application_ReentrantLock {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
ExecutorService service = Executors.newFixedThreadPool(2);
for (int i=0;i<2;i++){
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+"开始执行");
lock.lock();//ReentrantLock进行加锁
System.out.println(Thread.currentThread().getName()+"加锁");
Thread.sleep(1000);
lock.unlock();
System.out.println(Thread.currentThread().getName()+"解锁,结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
service.execute(runnable);
}
service.shutdown();
}
}
关键字synchronized与wait()/notify()、notifyAll()方法相结合可以实现等待/通知模式,类ReentrantLock也可以实现类似的功能,但需要借助于Condition对象。Condition类是JDK5中出现的类,使用它有更好的灵活性,比如可以实现多路通知功能,也就是在一个Lock对象里面可以创建多个Condition(即对象监视器实例),线程对象可以注册在指定的Condition中,从而可以有选择性地进行线程通知,在调度线程上更加灵活。
在使用notify()/notifyAll()方法进行通知时,被通知的线程却是由JVM随机选择的。但使用ReentrantLock结合Condition类是可以实现前面介绍过的"选择性通知",这个功能是非常重要的,而且在Condition类中是默认提供的。
而synchronized就相当于整个Lock对象中只有一个单一的Condition对象,所有的线程都注册在它一个对象的身上。线程开始notifyAll()时,需要通知所有的WATING线程,没有选择权,会出现相当大的效率问题。
condition对象的await()\signal()\signalAll()必须在获得lock.lock()占用锁之后调用,而且最后必须手动释放锁。
Condition的await()方法相当于Object的wait()方法,会释放锁;
Condition的signal()方法相当于Object类的notify()方法,Condition类的signalAll()方法相当于Object的notifyAll()方法,会唤醒对应的await()线程。
//ReentrantLock結合Condition实现等待/通知
//condition对象的await()\signal()\signalAll()
// 必须在获得lock.lock()占用锁之后调用,而且最后必须手动释放锁。
class application_ReentrantLock1 {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"start await");
condition.await();//Condition的await()方法相当于Object的wait()方法,会释放锁;
System.out.println(Thread.currentThread().getName()+"end await");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println(Thread.currentThread().getName()+"unlock");
lock.unlock();
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"start signal");
condition.signal();//signal()方法,会唤醒对应的await()线程。
System.out.println(Thread.currentThread().getName()+"end signal");
} catch (Exception e) {
e.printStackTrace();
}finally {
System.out.println(Thread.currentThread().getName()+"unlock");
lock.unlock();
}
}
});
t1.start();
t2.start();
}
}
使用ReentrantLock创建多个Condition对象之后可以实现唤醒指定的线程,这是控制部分线程行为的方便方式。可以理解为将线程分组,每一组对应一个condition对象。
//使用多个Condition实现等待/通知部分线程
class application_ReentrantLock2 {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Condition conditionA = lock.newCondition();
Condition conditionB = lock.newCondition();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"start await");
conditionA.await();//Condition的await()方法相当于Object的wait()方法,会释放锁;
System.out.println(Thread.currentThread().getName()+"end await");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println(Thread.currentThread().getName()+"unlock");
lock.unlock();
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"start signal");
conditionA.signal();//signal()方法,会唤醒对应的await()线程。
System.out.println(Thread.currentThread().getName()+"end signal");
} catch (Exception e) {
e.printStackTrace();
}finally {
System.out.println(Thread.currentThread().getName()+"unlock");
lock.unlock();
}
}
});
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"start await");
conditionB.await();//Condition的await()方法相当于Object的wait()方法,会释放锁;
System.out.println(Thread.currentThread().getName()+"end await");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println(Thread.currentThread().getName()+"unlock");
lock.unlock();
}
}
});
Thread t4 = new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+"start signal");
conditionB.signal();//signal()方法,会唤醒对应的await()线程。
System.out.println(Thread.currentThread().getName()+"end signal");
} catch (Exception e) {
e.printStackTrace();
}finally {
System.out.println(Thread.currentThread().getName()+"unlock");
lock.unlock();
}
}
});
t1.start();
t2.start();
t3.start();
t4.start();
}
}
//使用condition实现线程按顺序执行
class application_ReentrantLock3 {
volatile static int currentNum = 1;
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
for (int i=0;i<10;i++){
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
while (!String.valueOf(currentNum).equals(Thread.currentThread().getName())){
condition.await();//释放锁资源 然后等待
}
System.out.println(currentNum);
condition.signalAll();
currentNum++;
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
},(i+1)+"");
t.start();
}
}
}