AQS和JUC工具类

⼀、ReentrantLock重⼊锁

1.1> 概述

● 重⼊锁可以完全替代synchronized关键字。在JDK5.0的早期版本中,重⼊锁的性能远远好于 synchronized,但从JDK6.0开始,JDK在synchronized上做了⼤量的优化,使得两者的性能差距并 不⼤。重⼊锁对逻辑控制的灵活性要远远好于synchronized。
● 重⼊锁常⽤⽅法
在这里插入图片描述
● 下⾯是使⽤重⼊锁的简单示例:
在这里插入图片描述
之所以称之为重⼊锁,就是⼀个线程允许反复进⼊。当然,这⾥的反复仅仅局限于⼀个线程;如 果同⼀个线程多次获锁,那么在释放锁的时候,也必须释放相同次数。如果释放锁的次数多,那么 会得到⼀个java.lang.IllegalMonitorStateException异常,反之,如果释放锁的次数少,那么相当 于线程还持有这个锁。如下所示:
在这里插入图片描述

1.2> 中断响应 lockInterruptibly()

● 如果使⽤synchronized,要么获得锁,要么保持等待。⽽如果使⽤了重⼊锁,则提供了另⼀种可 能,那就是线程可以被中断。也就是在等待锁的过程中,程序可以根据需要取消对锁的请求。即: 如果⼀个线程正在等待锁,那么它依然可以收到⼀个通知,被告知⽆须再等待,可以停⽌⼯作了。 可以很好的应对死锁问题。示例如下所示:
在这里插入图片描述
在这里插入图片描述

1.3> 锁申请等待限时 tryLock(long time, TimeUnit unit)

除了等待外部通知之外,要避免死锁还有另外⼀种⽅式,就是限时等待。以下⾯为例,线程尝试 获得锁,如果没有获得锁,则等待5秒钟。如果5秒钟之后依然没有获得锁,则返回false,表示获得 锁失败。
在这里插入图片描述
tryLock()⽅法也可以不带参数直接运⾏。在这种情况下,当前线程会尝试获得锁,如果锁并未被其 他线程占⽤,则申请锁会成功,并⽴即返回true。如果锁被其他线程占⽤,则当前线程不会进 ⾏等待,⽽是⽴即返回false。这种模式不会引起线程等待,因此也不会产⽣死锁。
在这里插入图片描述

1.4> 公平锁和⾮公平锁

在⼤多数情况下,锁的申请都是⾮公平锁。系统只是会从这个锁的等待线程中随机选择⼀个。类似 ⼤家买票不去排队,乱哄哄的围在售票窗⼝前,售票员忙得焦头烂额,也顾不及谁先谁后,随便找 ⼀个⼈出票就完事⼉了。
在这里插入图片描述
当⼊参为true时,则采⽤公平锁⽅式。要求系统维护⼀个有序队列,因此公平锁的实现成本⽐较 ⾼,性能相对也⾮常低下。因此,默认情况下,锁是⾮公平的。如果没有特别的需求,也不需要使 ⽤公平锁。在这里插入图片描述

1.5> AQS源码解析

⼆、Condition重⼊锁的搭配类

在这里插入图片描述

  • Condition常⽤⽅法

在这里插入图片描述
在这里插入图片描述

三、Semaphore信号量

  • ⼴义上说,Semapore信号量是对锁的⼀种扩展;因ReentrantLock,⼀次都只允许⼀个线程访问某⼀资源,⽽信号量却可以指定多个线程同时访 问某⼀个资源。
  • 信息量主要提供了⼀下构造函数,必须要指定信号量的准⼊数,即:同时能申请多少个许可为⽆论是内部锁synchronized,还是重⼊锁
    在这里插入图片描述
    信息量主要⽅法如下所示
    在这里插入图片描述
    在这里插入图片描述

四、ReadWriteLock读写锁

ReadWriteLock是JDK5中提供的读写分离锁。它允许多个线程同时读。但是考虑到数据的完整性, 写写操作和读写操作间依然是需要相互等待和持有锁的。读写锁的访问约束情况如下所示:
在这里插入图片描述
下⾯例⼦中,我们使⽤普通锁,执⾏读写操作:在这里插入图片描述
在这里插入图片描述
下⾯例⼦中,我们使⽤读写锁(只需要将上⾯例⼦中openRWLock=true即可)执⾏读写操作,如
在这里插入图片描述
在这里插入图片描述

  • 所以,如果在系统中,读操作的次数远远⼤于写操作,那么读写锁就可以发挥最⼤的效果,提升系 统的性能。

五、CountDownLatch倒计时器

● CountDownLatch是⼀个多线程控制⼯具。⽤来控制线程的等待。设置需要countDown的数量 num,然后每⼀个线程执⾏完毕后,调⽤countDown()⽅法,⽽主线程调⽤await()⽅法执⾏等待, 直到num个⼦线程执⾏了countDown()⽅法 ,则主线程开始继续执⾏。在这里插入图片描述

六、CyclicBarrier循环栅栏

● CyclicBarrier与CountDownLatch⾮常类似,它⽀持计数器的反复使⽤,CyclicBarrier可以 理解为循环栅栏。CyclicBarrier可以接收⼀个参数作为Runnable barrierAction,每当计数器 ⼀次计数完成后——CyclicBarrier.await()时,系统会执⾏的动作。
在这里插入图片描述
CyclicBarrier.await()⽅法可能会抛出两种异常:⼀个是InterruptedException,也就是 在等待过程中,线程被中断,应该说这是⼀个⾮常通⽤的异常,⼤部分迫使线程等待的⽅法都可能 会抛出这个异常,使得线程在等待时依然可以响应外部紧急事件。另外⼀个异常则是CyclicBarrier 特有的BrokenBarrierException,⼀旦遇到这个异常,则表示当前的CyclicBarrier已经破损 了,可能系统已经没有办法等待所有线程到⻬了。如果继续等待,可能就是徒劳⽆功的,因此就此 结束吧。
在这里插入图片描述

七、LockSupport线程阻塞⼯具类

  • LockSupport是⼀个⾮常⽅便实⽤的线程阻塞⼯具,它可以在线程内任意位置让线程阻塞。和 Thread.suspend()相⽐,它弥补了由于resume()在前发⽣,导致线程⽆法继续执⾏的情况。和 Object.wait()⽅法相⽐,它不需要先获得某个对象的锁,也不会抛出InterruptedException 异常。
  • park()可以阻塞当前线程,其中每⼀个线程都有⼀个许可,该许可默认为[不可⽤]。如果该许可 是[可⽤]状态,那么park()⽅法会⽴即返回,消费这个许可,将该许可变更为[不可⽤]状态,流 程代码可以继续执⾏。如果该许可是[不可⽤]状态,那么park()⽅法将会阻塞; unpark⽅法,将指定线程的⼀个许可变为[可⽤]状态。如下表所示:
    在这里插入图片描述
    示例⼀:先执⾏unpark()⽅法再执⾏park()⽅法,也不会造成永久卡死线程。如下所示:
    在这里插入图片描述
    示例⼆:LockSupport.park()还能⽀持中断。但是它不会抛InterruptedException异常。 它只会默默的返回,但是我们可以从Thread.interrupted()等⽅法获得中断标记。
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值