总结篇(29)---Java并发及锁(3)Lock

本文详细介绍了Lock接口的功能和使用方法,包括其提供的多种获取锁的方式及其实现原理。对比了Lock与synchronized关键字的区别,并探讨了为何需要Lock。
部署运行你感兴趣的模型镜像

Lock

  • 是一种用于控制多个线程对共享资源的访问工具

一、Lock使用


public interface Lock {
    void lock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long var1, TimeUnit var3) throws InterruptedException;
    void unlock();
    Condition newCondition();
}


它是个接口类,有6个方法,前面4个就是用来获取锁的,第5个用来释放锁的,第6个用来设置等待和通知的。

1. lock():普通获取锁的方法
2. lockInterruptibly():通过这个方法获取锁的话,如果线程正在等待获取锁,则这个线程能够相应中断,即中断线程的等待状态。
3. tryLock():具有返回值,得到锁返回true,否则返回false。
4. tryLock(long var1, TimeUnit var3):跟上面一样也有返回值,多了等待时间,第一个参数是要等待的时间,第二个参数是时间单位。
5. unlock():释放锁
6. newCondition():设置等待和通知的

  • lock使用
 private Lock lock = new ReentrantLock();
    public void testLock(String name) {
        lock.lock();
        System.out.println(Thread.currentThread().getName() + ",Request Lock...");
        try {
            for (int i = 0; i < 100; i++) {
                y++;
                System.out.println(name + "-->CurrThread:" 
                            +Thread.currentThread().getName() + " y=" + y);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            System.out.println(Thread.currentThread().getName() 
                            + ",Release Lock ...");
        }
    }


二、Lock原理


        因为ReentrantLock实现了Lock接口,我们可以观察ReentrantLock怎么实现。


        经观察ReentrantLock把所有Lock接口的操作都委派到一个Sync类上,该类继承了AbstractQueuedSynchronizer(一般简称AQS)

static abstract class Sync extends AbstractQueuedSynchronizer


        Sync又有两个子类:(区别实现公平锁和非公平锁)

final static class NonfairSync extends Sync 

final static class FairSync extends Sync 

        ReentrantLock的公平锁和非公平锁的实现差异主要体现在 获取锁时的策略 上,其底层基于 AbstractQueuedSynchronizer(AQS)框架。

行为

公平锁(FairSync)

非公平锁(NonfairSync)

锁获取策略

严格按队列顺序(先到先得)

允许新线程插队抢占

性能

低(上下文切换频繁)

高(减少线程挂起和唤醒)

饥饿问题

避免饥饿

可能引发线程饥饿

实现差异

tryAcquire()

中检查队列

lock()

直接尝试 CAS,不检查队列


AQS提供了一种实现阻塞锁和一系列依赖FIFO等待队列的同步器的框架。


        CLH解释:(Craig,Landin,and Hagersten locks)是一种基于链表的可扩展、高性能、公平的自旋锁,申请线程只在本地变量上自旋,它不断轮询前驱的状态,如果发现前驱的释放了锁就结束自旋。

  • 核心数据结构:双向链表 + state(锁状态)
  • 底层操作:CAS

AQS中的int类型的state值,这里就是通过CAS(乐观锁)去修改state的值。lock的基本操作还是通过乐观锁来实现的。

1.获取锁通过CAS修改state的值,

2.如果是没有获取到锁,会尝试再次通过CAS获取一次锁,还是没有的话,会将当前线程加入到等待队列中。当当前线程到头部的时候,尝试CAS更新锁状态,如果更新成功表示该等待线程获取成功,从头部移除。

public final void acquire(int arg) {
        /***
        *  1.tryAcquire:会尝试再次通过CAS获取一次锁。
        *  2.addWaiter:通过自旋CAS,将当前线程加入上面锁的双向链表(等待队列)中。
        *  3.acquireQueued:通过自旋,判断当前队列节点是否可以获取锁。
        ***/
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

3.释放锁就是对AQS中的状态值State进行修改,同时更新下一个链表中的线程等待节点。

通过上述实现过程可以看出,lock大量使用CAS+自旋。



备注:

  • 1.为什么有了synchronized还需要Lock?

        (1)效率低:锁的释放情况少,试图获得锁时不能设定超时,不能中断一个正在试图获取/释放锁的进程。
        (2)不够灵活:加锁和释放的时机单一,每个锁仅有单一的条件(某个对象),可能是不够的
        (3)无法知道是否成功获取到锁

  • 2.synchronized与Lock区别?
区别类型synchronizedLock
本身是java中的关键字是一个接口
使用范围可以用在方法上,也可以用在特定代码块上需要指定起始位置和终止位置
实现方式托管给JVM执行的通过代码实现的
是否支持超时永久阻塞等待支持超时获取锁,超时后释放资源
性能上在竞争不是很激烈的情况下,synchronized的性能优于ReentrantLock(Lock实现类)竞争激烈的情况下synchronized的性能下降的非常快,而ReentrantLock(Lock)则基本不变
锁机制获取锁和释放锁的方式都是在块结构中,当获取多个锁时,必须以相反的顺序释放锁,并且是自动解锁(发生异常时会自动执行)需要开发人员手动释放,并且必须在finally中释放,否则会引起死锁(没有主动释放会造成死锁现象)

更多java基础总结(适合于java基础学习、java面试常规题):

总结篇(1)---复用类

总结篇(2)---多态

总结篇(3)---内部类 (1)内部类的基本概念

总结篇(4)---内部类 (2)内部类之静态内部类

总结篇(5)---内部类 (3)内部类之成员内部类

总结篇(6)---内部类 (4)内部类之局部内部类

总结篇(7)---内部类 (5)内部类之匿名内部类

总结篇(8)---序列化

总结篇(9)---字符串及基本类 (1)字符串及基本类之基本数据类型

总结篇(10)---字符串及基本类 (2)字符串及基本类之java中公共方法及操作

总结篇(11)---字符串及基本类 (3)String对象

总结篇(12)---字符串及基本类 (4)Integer对象

总结篇(13)--- Java注解及元注解

总结篇(14)---JVM(java虚拟机) (1)JVM虚拟机概括

总结篇(15)---JVM(java虚拟机) (2)类加载器

总结篇(16)---JVM(java虚拟机) (3)运行时数据区

总结篇(17)---JVM(java虚拟机) (4)垃圾回收

总结篇(18)---JVM(java虚拟机) (5)垃圾回收算法

总结篇(19)---JVM(java虚拟机) (6)JVM调优

总结篇(20)---反射

总结篇(21)---Java IO

总结篇(22)---Java 进程

总结篇(23)---Java线程及其相关(1)线程介绍

总结篇(24)---Java线程及其相关(2)多线程及其问题

总结篇(25)---Java线程及其相关(3)线程池及其问题

总结篇(26)---Java线程及其相关(4)ThreadLocal

总结篇(27)---Java并发及锁(1)Synchronized

总结篇(28)---Java并发及锁(2)Volatile

总结篇(29)---Java并发及锁(3)Lock

总结篇(30)---Java并发及锁(4)常见锁及分类

总结篇(31)---JUC工具类(1)CountDownLatch

总结篇(32)---JUC工具类(2)CyclicBarrier

总结篇(33)---JUC工具类(3)Semaphore

总结篇(34)---JUC工具类(4)Exchanger

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sun cat

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值