前言
上一篇文章,我们一起学习了synchronized关键字控制的同步锁,从本篇开始,将开始介绍JUC包中的锁,相比同步锁,JUC包中的锁的功能更加强大,它为锁提供了一个框架,该框架允许更灵活地使用锁。
1、ReentrantLock介绍
ReentrantLock是一个可重入的互斥锁,又被称为“独占锁”,可重入的意思是,ReentrantLock锁可以被单个线程多次获取,“独占锁”的意思是,在同一个时间点只能被一个线程锁持有。ReentrantLock分为“公平锁”和“非公平锁”,在“公平锁”的机制下,线程依次排队获取锁;而“非公平锁”在锁是可获取状态时,不管自己是不是在队列的开头都会获取锁。
2、ReentrantLock的函数
// 创建一个 ReentrantLock ,默认是“非公平锁”。
ReentrantLock()
// 创建策略是fair的 ReentrantLock。fair为true表示是公平锁,fair为false表示是非公平锁。
ReentrantLock(boolean fair)
// 查询当前线程保持此锁的次数。
int getHoldCount()
// 返回目前拥有此锁的线程,如果此锁不被任何线程拥有,则返回 null。
protected Thread getOwner()
// 返回一个 collection,它包含可能正等待获取此锁的线程。
protected Collection<Thread> getQueuedThreads()
// 返回正等待获取此锁的线程估计数。
int getQueueLength()
// 返回一个 collection,它包含可能正在等待与此锁相关给定条件的那些线程。
protected Collection<Thread> getWaitingThreads(Condition condition)
// 返回等待与此锁相关的给定条件的线程估计数。
int getWaitQueueLength(Condition condition)
// 查询给定线程是否正在等待获取此锁。
boolean hasQueuedThread(Thread thread)
// 查询是否有些线程正在等待获取此锁。
boolean hasQueuedThreads()
// 查询是否有些线程正在等待与此锁有关的给定条件。
boolean hasWaiters(Condition condition)
// 如果是“公平锁”返回true,否则返回false。
boolean isFair()
// 查询当前线程是否保持此锁。
boolean isHeldByCurrentThread()
// 查询此锁是否由任意线程保持。
boolean isLocked()
// 获取锁。
void lock()
// 如果当前线程未被中断,则获取锁。
void lockInterruptibly()
// 返回用来与此 Lock 实例一起使用的 Condition 实例。
Condition newCondition()
// 仅在调用时锁未被另一个线程保持的情况下,才获取该锁。
boolean tryLock()
// 如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。
boolean tryLock(long timeout, TimeUnit unit)
// 试图释放此锁。
void unlock()
3、生产者消费者代码演示
public class ReentrantLockTest {
public static void main(String[] args) {
Depository depository = new Depository(100);
Producer producer = new Producer(depository);
Customer customer = new Customer(depository);
producer.produce(8);
customer.customer(8);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("%s depository --> size=%d\n", Thread.currentThread().getName(),depository.getSize());
}
}
//仓库
class Depository {
//仓库容量
private Integer depository;
//仓库剩余的容量
private Integer size;
// 独占锁
private Lock lock;
//重试线程集合
private static Map<String,Integer> reTryMap = new HashMap<>(32);
//重试次数
private static final int RETRY_TIME = 3;
public Integer getSize() {
return size;
}
public Depository(int depository){
this.depository = depository;
this.lock = new ReentrantLock();
this.size = 0;
}
public void increment(int number){
lock.lock();
try {
if(size < depository){
size += number;
System.out.printf("%s produce --> size=%d\n",
Thread.currentThread().getName(),number);
}
} finally {
lock.unlock();
}
}
public void decrease(int number) {
lock.lock();
try {
if (size >= number) {
size -= number;
System.out.printf("%s decrease --> size=%d\n",
Thread.currentThread().getName(),number);
} else {
//启动重试机制
if(reTryMap.containsKey(Thread.currentThread().getName())){
Integer num = reTryMap.get(Thread.currentThread().getName());
if(num < RETRY_TIME){
//进行重试
reTryMap.put(Thread.currentThread().getName(),num+1);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
decrease(number);
} else {
//超过重试次数的移除
reTryMap.remove(Thread.currentThread().getName());
}
} else {
reTryMap.put(Thread.currentThread().getName(),1);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
decrease(number);
}
}
} finally {
lock.unlock();
}
}
}
//生产者
class Producer {
private Depository depot;
public Producer(Depository depot) {
this.depot = depot;
}
// 新建numer个线程向仓库中生产产品。
public void produce(final int numer) {
for(int i=1; i<numer; i++){
final int val = i;
new Thread() {
public void run() {
depot.increment(val);
}
}.start();
}
}
}
//消费者
class Customer {
private Depository depot;
public Customer(Depository depot) {
this.depot = depot;
}
// 新建number个线程向仓库中消费产品。
public void customer(final int numer) {
for(int i=1; i<numer; i++){
final int val = i;
new Thread() {
public void run() {
depot.decrease(val);
}
}.start();
}
}
}
执行结果:
Thread-0 produce --> size=1
Thread-4 produce --> size=5
Thread-1 produce --> size=2
Thread-5 produce --> size=6
Thread-3 produce --> size=4
Thread-7 decrease --> size=1
Thread-11 decrease --> size=5
Thread-8 decrease --> size=2
Thread-12 decrease --> size=6
Thread-2 produce --> size=3
Thread-6 produce --> size=7
Thread-9 decrease --> size=3
Thread-13 decrease --> size=7
Thread-10 decrease --> size=4
main depository --> size=0
结束语
上面的代码注释比较详细了,就不再说明了,本篇主要介绍ReentrantLock的基本用法,下一篇,将详细介绍ReentrantLock获取锁和释放锁的过程。