java并发(4)——ReentrantLock,Condition,Semaphore

ReentrantLock

在Synchronized优化以前,synchronized的性能是比ReenTrantLock差很多的,但是自从jdk1.6开始,Synchronized引入了偏向锁,轻量级锁(自旋锁)后,两者的性能就差不多了,在两种方法都可用的情况下,官方甚至建议使用synchronized,其实synchronized的优化我感觉就借鉴了ReenTrantLock中的CAS技术。都是试图在用户态就把加锁问题解决,避免进入内核态的线程阻塞。
看一下ReentrantLock的接口:
这里写图片描述

简单的例子

这里写图片描述
运行结果:
这里写图片描述
如果在不加锁的情况下运行结果,最终的数字不确定(接近10000000):
这里写图片描述

ReenTrantLock独有的能力:

  1. ReenTrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。
  2. ReenTrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。
  3. ReenTrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。

中断机制

来看一下ReentrantLock相对于synchronized的第一点特点:ReenTrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。
这里写图片描述
这里写图片描述
运行结果:
这里写图片描述

公平锁

在大多数情况下锁的申请都是非公平的,如果线程1首先申请的锁,之后线程2申请锁,当这把锁可用的时候,系统只会从这个锁的等待队列中随机挑选一个。这样容易造成某些线程饿死。而公平锁是排队的遵循先到先得的原则:
这里写图片描述
公平锁运行结果:
这里写图片描述
非公平锁运行结果:
这里写图片描述

Condition

如果理解Object.wait()和Object.notify()那么Condition就比较好理解了,wait和notify是和synchronized关键字配合使用
Condition接口的方法如下:
这里写图片描述

void await() throws InterruptedException

当前线程进入等待状态,直到被通知(signal)或者被中断时,当前线程进入运行状态,从await()返回;

void awaitUninterruptibly()

当前线程进入等待状态,直到被通知,对中断不做响应;

long awaitNanos(long nanosTimeout) throws InterruptedException

await()的返回条件基础上增加了超时响应,返回值表示当前剩余的时间,如果在nanosTimeout之前被唤醒,返回值 = nanosTimeout - 实际消耗的时间,返回值 <= 0表示超时;

boolean await(long time, TimeUnit unit) throws InterruptedException

同样是在await()的返回条件基础上增加了超时响应,与接口3不同的是:

可以自定义超时时间单位;
返回值返回true/false,在time之前被唤醒,返回true,超时返回false。

boolean awaitUntil(Date deadline) throws InterruptedException

当前线程进入等待状态直到将来的指定时间被通知,如果没有到指定时间被通知返回true,否则,到达指定时间,返回false;

void signal()

唤醒一个等待在Condition上的线程;

void signalAll()

唤醒等待在Condition上所有的线程。

示例:
这里写图片描述
运行结果:
这里写图片描述
和wait/notify一样,当线程使用condition.await()的时候,要求线程持有相关的锁,当线程调用condition.await()之后,这个线程会释放持有的锁,并进入等待状态。当调用notify()的时候系统会挑选一个等待在该条件下的线程并唤醒之。

在JDK内部,重入锁和Condition被广泛使用,以ArrayBlockingQueue为例:
这里写图片描述
这里写图片描述
这里写图片描述

信号量:Semaphore

信号量为多个线程协作提供了更强大的控制方法,无论是ReentrantLock还是Synchronized一次都只允许一个线程访问一个资源。信号量允许多个线程同时访问同一个资源:
看下Semaphore的接口定义:
这里写图片描述
有两个构造函数:
这里写图片描述
permits表示一次允许多少个线程, fair表示是否公平锁

示例:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值