1、什么是ReentranLock?
ReentranLock,是一个可重入的互斥锁,又被称为“独占锁”;ReentrantLock锁在同一个时间点只能被一个线程锁持有;而可重入的意思是,ReentrantLock锁,可以被单个线程多次获取。
2、ReentranLock的组成
继承关系:实现Lock接口;
通过Sync类(Sync类继承于AQS)实现同步状态更新,它有FairSync和NonFairSync两个具体实现类来实现公平锁和非公平锁;
public class ReentrantLock implements Lock, java.io.Serializable {
//内部类Sync,继承自AQS
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {...}
//非公平锁
static final class NonfairSync extends Sync {...}
//公平锁
static final class FairSync extends Sync {...}
//构造方法,Sync默认为非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
//带参构造方法,true为公平锁,false为非公平锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
//下面还有一大堆方法...
3、ReentranLock用法示例
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Depot {
//仓库产品的数量
private int size;
//独占锁
private Lock lock;
//无参构造方法
public Depot() {
this.size = 0;
this.lock = new ReentrantLock();
}
public void produce(int val) {
lock.lock();
try {
size = size + val;
System.out.println(Thread.currentThread().getName()
+ " produce:" + val + " size:" + size);
} finally {
lock.unlock();
}
}
public void consume(int val) {
lock.lock();
try {
size = size - val;
System.out.println(Thread.currentThread().getName()
+ " consume:" + val + " size:" + size);
} finally {
lock.unlock();
}
}
}
//生产者
class Producer {
private Depot depot;
public Producer(Depot depot) {
this.depot = depot;
}
//新建一个线程在仓库中生产产品
public void produce(int val) {
new Thread() {
public void run() {
depot.produce(val);
}
}.start();
}
}
class Consumer {
private Depot depot;
public Consumer(Depot depot) {
this.depot = depot;
}
//新建一个线程在仓库中消费产品
public void consume(int val) {
new Thread() {
public void run() {
depot.consume(val);
}
}.start();
}
}
public class Test1 {
public static void main(String[] args) {
Depot depot = new Depot();
Consumer consumer = new Consumer(depot);
Producer producer = new Producer(depot);
producer.produce(60);
producer.produce(120);
consumer.consume(90);
consumer.consume(150);
producer.produce(110);
}
}
运行结果截图:
可以看出,ReentranLock通过lock.lock()和lock.unlock()两个方法获取锁和释放锁,与synchronized作用相似,可以保证每次只有一个线程获取到锁。
PS:上面的例子只用于展示ReentranLock的基本使用,存在部分一些不合实际的情况,如仓库没有做负数检测也没有做容量检测,运行时就有可能出现下面这种不合实际的情况。
参考资料
Java多线程系列–“JUC锁”02之 互斥锁ReentrantLock——http://www.cnblogs.com/skywang12345/p/3496101.html