java多线程之ReentrantLock互斥锁

前言

上一篇文章,我们一起学习了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获取锁和释放锁的过程。

原创文章 55 获赞 76 访问量 17万+

猜你喜欢

转载自blog.csdn.net/cool_summer_moon/article/details/105912547