3.2 内置锁、显示锁、可重入锁、读写锁

一、显示锁

1、synchronized和lock辨析

Java中的synchronized是一种内置锁,其中加锁解锁的顺序已经被固化,并且没有提供一些其他可供选择的操作,java还提供了一种显示锁lock,它提供了一系列的方法供我们使用:可以尝试获取锁,超时获取锁、获取锁可以被中断,如果使用锁时有以上3中业务需求,则需要使用lock,否则使用synchronized即可。

2、ReentrantLock可重入锁

java中的lock是一个接口,Java ReentrantLock实现了lock,是可以被实例化的类,同时它也支持可重入的机制。

  • 概念:在同一个线程中获取锁之后再次获取锁,可以获取成功的就是可重入锁
  • 场景:可重入锁的使用场景是哪些,一个比较典型的就是递归,递归调用很明显如果方法中存在加锁的操作,那么就会存在一个线程连续对同一把锁进行加锁
  • 举例实现不可重入锁、可重入锁
2.1不可重入锁
package cn.enjoy.controller.thread;
/**
 * @author:wangle
 * @description:
 * @version:V1.0
 * @date:2020-03-28 14:22
 **/
public class Lock {
    private boolean isLock = false;
    //因为需要使用到wait和notify在这里使用了synchronized
    public synchronized void lock()throws InterruptedException{
        while(isLock){
            wait();
        }
        isLock=true;
    }
    public synchronized void unLock(){
        isLock=false;
        notify();
    }
    public class Count{
        Lock lock = new Lock();
        public void out()throws InterruptedException{
            lock.lock();
            doLock();
            lock.unLock();
        }
        public void doLock()throws InterruptedException{
            lock.lock();
            Thread.sleep(1000);
            lock.unLock();
        }
    }
}

上述程序很明显第二次被加锁的时候就会被阻塞

2.2可重入锁
package cn.enjoy.controller.thread;

/**
 * @author:wangle
 * @description:
 * @version:V1.0
 * @date:2020-03-28 14:22
 **/
public class Lock {
    private boolean isLock = false;
    Thread currentThread = null;
    int lockCount = 0;
    //因为需要使用到wait和notify在这里使用了synchronized
    public synchronized void lock()throws InterruptedException{
        Thread thread = Thread.currentThread();
        while(isLock && thread != currentThread){
            wait();
        }
        isLock=true;
        currentThread=thread;
        lockCount+=1;
    }
    public synchronized void unLock(){
        Thread thread = Thread.currentThread();
        while(thread == currentThread){
            lockCount--;
            if(lockCount==0){
                isLock=false;
                currentThread=null;
                notify();
            }
        }
    }
    public class Count{
        Lock lock = new Lock();
        public void out()throws InterruptedException{
            lock.lock();
            doLock();
            lock.unLock();
        }
        public void doLock()throws InterruptedException{
            lock.lock();
            Thread.sleep(1000);
            lock.unLock();
        }
    }
}

上述程序就是一个可重入锁,当第一个线程进行加锁的时候由于currentThread==null,不会进入while进行wait,再次进入的时候发现currentThread是等于当前线程的,也不会进入到while循环进行等待,两次都是进行了lockCount的自增,解锁时如果是当前线程获取锁则去lockCount自减,如果减到0则释放锁。
java中的ReentrantLock可重入锁也是基于这种机制进行的。

2.3、公平锁、非公平锁
  • 概念
    在时间上,先对锁进行获取的请求一定先被满足,就是公平锁,否则就是非公平锁。
  • 公平锁和非公平锁的效率问题
    举例:
    1、线程A获取了锁
    2、线程B来请求获取锁,发现锁已经被占有,则线程B被挂起
    3、线程C来进行获取锁。

这时A释放了锁
公平锁的操作如下
1、唤醒B线程,执行某些业务操作,再释放锁,这时候C很有可能已经被挂起了,因为长时间未获取到锁,这时还要唤醒C再去执行业务操作
非公平锁的操作如下
1、线程C在尝试获取锁的时候还未被挂起,A释放了锁,则直接获取锁,执行相关操作,再唤醒B线程,获取锁执行操作。

可以看出非公平锁的效率是比较高的,省去了B的唤醒操作的时间,还有可能省去C的唤醒时间。

ReentrantLock提供2个重载的构造函数,带有boolean参数的可以指定是否是公平锁

3、读写锁ReadWriteLock

ReadWriteLock是一个接口,ReentrantReadWriteLock实现了这个接口
Synchronized、ReentrantLock都是排他锁,一个线程持有锁其他线程都得等待其释放后才能重新获取锁执行。
读写锁:同一时刻允许多个线程同时访问,但是写线程访问的时候,其他所有读写线程都将被阻塞,最适宜读多写少的场景。

4、lock、condition

condition接口有比较重要的两个方法,signal
、await。类似于Object的wait和notify方法,功能也是如出一辙。都是用于实现等待于通知机制。用法几乎一毛一样,在这里就不演示了,有兴趣的小伙伴可以去了解一下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值