004-并发工具类Lock分析

并发工具类

工具类,顾名思义就是解决一类问题的工具
所以工具类的了解一定要明白这个工具是用来处理什么问题的
而这个问题是由什么原因造成的
而并发工具类就是在多线程提升性能的前提下保证线程安全的工具

synchronized的问题

synchronized作为java提供最基础的同步工具
使用他可以控制执行一段代码同时只能由一个线程
但是锁的持有和释放是不能由开发人员决定的
并且对锁的获取是不能停止的,一旦一个获取锁的线程卡死并没有释放锁
那么在等待这个锁的所有线程都会卡死
那在实际业务中我需要更加灵活的控制尝试获取锁的持续时间该怎么办呢?

java给我们提供了一些列的锁工具,也就是一系列的Lock实现
在了解这些Lock实现前我们先来了解下最顶层的Lock接口

Lock的接口

方法

在这里插入图片描述
下边是翻译的方法上的注释:

  1. void lock();
    尝试获取锁,如果获取不到则休眠到获取为止
  2. void lockInterruptibly() throws InterruptedException;
    尝试获取锁,如果获取不到则休眠到获取为止或被其他线程中断当前线程。
  3. boolean tryLock();
    尝试获取锁,如果获取则返回true,如果获取不到,则立即返回false
  4. boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    尝试在等待时间内获取锁
    如果锁可用,则立即返回 true
    如果锁不可用,则线程进入休眠状态,直到
  • 锁由当前线程获取:返回 true
  • 其他线程中断当前线程:抛出 InterruptedException 异常并清除线程中断状态
  • 指定的等待时间已过:返回 false(如果配置时间<=0则不会等待)
  1. void unlock();
    释放锁
  2. Condition newCondition();
    返回绑定到此Lock实例的新Condition实例。
    线程获取锁之后可以调用 Condition.await() 释放锁并等待
    在被唤醒之后重新获取锁
    Condition也是一个接口
    我们来看下接口的方法
    在这里插入图片描述
    其实就是等待和唤醒的规范,可以做到线程间的相互影响
    多用来实现等待/通知机制

ReentrantLock:可重入的互斥锁

Lock的最基础的实现,synchronized 的平替
Java推荐的最佳实践:
在这里插入图片描述

可重入

获取锁的线程
在执行到重新需要获取这把锁的地方,可以直接进入
比如递归调用
下边两个方法都是可重入的
在这里插入图片描述
在这里插入图片描述

公平与非公平

公平先申请锁的线程先获取锁
非公平后申请锁的线程可能先获取锁
为了提高性能,ReentrantLocal默认非公平
在这里插入图片描述

Semaphore:信号量(实现类)

控制同时访问某个资源的线程数我们就可以用信号量
和独占锁的区别就是:可每次允许多个线程访问
可以简单理解为一个带有 + -能力的计数器
如:

  • 限流
  • 资源池
    在这里插入图片描述
    意思就是首先设置允许通过数量Semaphore(int permits)
    然后使用tryAcquire()请求,如果允许通过则计数器-1返回true
    如果计数器已经是0了就不允许通过,返回false
    使用完release()释放资源则计数器+1

在这里插入图片描述

CountDownLatch:闭锁(实现类)

我们在实际业务中有可能需要了解多线程的执行情况
如:一个接口内部有3个并发请求处理,我需要在这三个并发结束的时候组装返回,就可以用CountDownLatch
CountDown:倒计时的意思
在这里插入图片描述
使用**CountDownLatch(int count)设置一个初始值
传入异步线程内部,在线程执行完毕后调用
countDown()倒计时-1
在外部线程执行
boolean await(long timeout, TimeUnit unit)**等待倒计时为0的时候,继续向下执行

例子分析

下边是Java自带的例子
在这里插入图片描述
范例中 mian线程添加了N个异步Worker,但是Worker直接因为startSignal阻塞
等待 doSomethingElse() 执行完毕,startSignal 倒计时-1
因为到0了所以startSignal 自动唤醒所有等待
也就是所有Woker开始执行,在执行完doWork() 后 doneSignal 倒计时 -1
等N个线程都执行完了唤醒doneSgnal.await() 线程,也就是main线程

注意点

工作中一般使用带有时间的等待
并且在finally中使用 countDown方法
latch只能用一次

但是特殊场景中我们的循环可能不止一次
比如我有2个5批的任务需要并行处理
java就提供了一个回环屏障

CyclicBarrier:回环屏障

其实类似于之前的倒计时计数器
但是这个回环屏障,任务等待的时候就会自动计数器-1
到零的时候会

  • 自动执行指定的任务
  • 唤醒所有等待的线程
  • 重置计数器

方法

在这里插入图片描述

示例解析

在这里插入图片描述
设置回环屏障的计数值为N,并设置计数器为0执行 barrierAction任务
提交N个Worker,等待所有Worker执行完processRow进入等待
就真实开始执行 barrierAction方法 也就是mergeRows
此时 barrier这个回环屏障其实是可以重复利用的

在这里插入图片描述

CountDownLatch 和 CyclicBarrier区别

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值