高并发编程之ReentrantLock工具类讲解

一、ReentrantLock介绍
①、ReentrantLock实现了Lock接口,加锁和解锁都需要显式写出,注意一定要在适当时候unlock。
②、可重入锁。可重入锁是指同一个线程可以多次获取同一把锁。也是在实际编程中使用频率很高的一个锁,支持重入性,表示能够对共享资源能够重复加锁,即当前线程获取该锁再次获取不会被阻塞
③、可中断锁。可中断锁是指线程尝试获取锁的过程中,是否可以响应中断。synchronized是不可中断锁,而ReentrantLock则提供了中断功能。
④、公平锁与非公平锁。公平锁是指多个线程同时尝试获取同一把锁时,获取锁的顺序按照线程达到的顺序,而非公平锁则允许线程“插队”。synchronized是非公平锁,而ReentrantLock的默认实现是非公平锁,但是也可以设置为公平锁。

注意:使用重入锁进行加锁是一种显式操作,通过何时加锁与释放锁使重入锁对逻辑控制的灵活性远远大于synchronized关键字。同时,需要注意,有加锁就必须有释放锁,而且加锁与释放锁的分数要相同

二、ReentrantLock相对于synchronized的优势
①、ReentrantLock的优势在于它更灵活、更强大,除了常规的lock()、unlock()之外,还有lockInterruptibly()、tryLock()方法,支持中断、超时。
②、ReentrantLock默认使用非公平锁是基于性能考虑,公平锁为了保证线程规规矩矩地排队,需要增加阻塞和唤醒的时间开销。如果直接插队获取非公平锁,跳过了对队列的处理,速度会更快。
③、可以添加多个检控条件, 如果使用synchronized,则只能使用一个. 使用 reentrant locks 可以有多个wait()/notify() 队列. [译注:直接多new 几个ReentrantLock就可以了,不同的场景/条件用不同的ReentrantLock ]。
④、可以控制线程得到锁的顺序,也就是有公平锁(按照进入顺序得到资源),也可以不按照顺就像.synchronized 一样。
⑤、可以查看锁的状态, 锁是否被锁上了。
⑥可以查看当前有多少线程再等待锁。

三、Java代码示例
①、lock()方法:获取锁,如果锁不可用,出于线程调度目的,将禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态。

package chapter3.locks;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author czd
 */
public class ReentrantLockTest {
    /**
     * 非公平锁,当ReentrantLock(true)时是公平锁,都不是绝对公平,只是相对公平
     */
    private static final ReentrantLock lock = new ReentrantLock();
    
    public static void main(String[] args) {
        for(int i = 0; i < 2; i++){
            new Thread(){
                @Override
                public void run() {
                    needLock();
                }
            }.start();
        }
    }

    public static void needLock(){
        try {
            //不可被中断
            lock.lock();
            System.out.println(Thread.currentThread().getName()+">>>needLock()方法的效果与needLockLikeSyn()一样,但是速率比它快一点!");
            TimeUnit.SECONDS.sleep(2);
            System.out.println("任务结束!");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    /**
     * 这个方法实现的是利用synchronized关键字加锁
     */
    public static void needLockLikeSyn(){
        synchronized (ReentrantLockTest.class){
            try {
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName()+">>>这个方法的效果与needLock()一样,但是速率比它慢一点!");
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

输出结果
在这里插入图片描述

②、lockInterruptibly()方法:支持对锁获取的中断。

package chapter3.locks;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author czd
 */
public class ReentrantLockTest {
    /**
     * 非公平锁,当ReentrantLock(true)时是公平锁,都不是绝对公平,只是相对公平
     */

    private static final ReentrantLock lock = new ReentrantLock();


    public static void main(String[] args) {
        for(int i = 0; i < 2; i++){
            new Thread(){
                @Override
                public void run() {
                    needLockInterruptibly();
                }
            }.start();
        }
    }

  
    public static void needLockInterruptibly(){
        try {
            //当抢不到锁时,该线程允许被打断
            lock.lockInterruptibly();
            System.out.println(Thread.currentThread().getName()+">>>needLockInterruptibly()方法的效果与needLockLikeSyn()一样,但是速率比它快一点!");
            TimeUnit.SECONDS.sleep(2);
            System.out.println("任务结束!");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    /**
     * 这个方法实现的是利用synchronized关键字加锁
     */
    public static void needLockLikeSyn(){
        synchronized (ReentrantLockTest.class){
            try {
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName()+">>>这个方法的效果与needLock()一样,但是速率比它慢一点!");
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

输出结果
在这里插入图片描述

③、tryLock()方法:如果锁可用,则获取锁,并立即返回值 true。如果锁不可用,则此方法将立即返回值 false。

package chapter3.locks;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author czd
 */
public class ReentrantLockTest {
    /**
     * 非公平锁,当ReentrantLock(true)时是公平锁,都不是绝对公平,只是相对公平
     */

    private static final ReentrantLock lock = new ReentrantLock();


    public static void main(String[] args) {
        for(int i = 0; i < 2; i++){
            new Thread(){
                @Override
                public void run() {
                    needTryLock();
                }
            }.start();
        }
    }

    public static void needTryLock(){
        if (lock.tryLock()){
            try {
                System.out.println(Thread.currentThread().getName()+">>>needTryLock()方法的效果与needLockLikeSyn()一样,但是速率比它快一点!");
                TimeUnit.SECONDS.sleep(2);
                System.out.println("任务结束!");
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }else{
            System.out.println(Thread.currentThread().getName() + ">>>没有获得锁!");
        }
    }

    /**
     * 这个方法实现的是利用synchronized关键字加锁
     */
    public static void needLockLikeSyn(){
        synchronized (ReentrantLockTest.class){
            try {
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName()+">>>这个方法的效果与needLock()一样,但是速率比它慢一点!");
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

输出结果
在这里插入图片描述

④、tryLock(long time,TimeUnit unit)方法:如果锁在给定的等待时间内空闲,并且当前线程未被 中断,则获取锁。

package chapter3.locks;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author czd
 */
public class ReentrantLockTest {
    /**
     * 非公平锁,当ReentrantLock(true)时是公平锁,都不是绝对公平,只是相对公平
     */

    private static final ReentrantLock lock = new ReentrantLock();


    public static void main(String[] args) {
        for(int i = 0; i < 2; i++){
            new Thread(){
                @Override
                public void run() {
                   try {
                        needTryLock(2);
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }.start();
        }
    }


    public static void needTryLock(long seconds) throws InterruptedException{
        if (lock.tryLock(seconds,TimeUnit.SECONDS)){
            try {
                System.out.println(Thread.currentThread().getName()+">>>needTryLock()方法的效果与needLockLikeSyn()一样,但是速率比它快一点!");
                TimeUnit.SECONDS.sleep(5);
                System.out.println("任务结束!");
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }else{
            System.out.println(Thread.currentThread().getName() + ">>>在"+seconds+"秒内没有获得锁!");
        }
    }

    /**
     * 这个方法实现的是利用synchronized关键字加锁
     */
    public static void needLockLikeSyn(){
        synchronized (ReentrantLockTest.class){
            try {
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName()+">>>这个方法的效果与needLock()一样,但是速率比它慢一点!");
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

输出结果
在这里插入图片描述

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值