Lock的使用
程序员文章站
2022-03-09 18:58:56
...
Lock的使用
lock也能实现同步效果,而且使用更加方便
1.ReentrantLock类的使用
2.ReentrantReadWriteLock类的使用
使用ReentrantLock类
java多线程中,使用synchronized来实现线程之间的互斥,但在jdk1.5之后增加了ReentrantLock类,也能达到同样的效果,在扩展功能上
也更加强大,如嗅探锁定,多路分支通知等,而且使用也更加灵活。
1.使用ReentrantLock实现同步:测试1
Lock lock = new ReentrantLock();
获取锁lock.lock();
释放锁lock.unlock();
2.使用ReentrantLock实现同步:测试2
lock.lock();使用的是对象监视器,其它线程只能等待锁被释放时再次争抢。
3.使用Condition实现等待/通知:错误用法与解决
类ReentrantLock需要借助Condition对象实现wait()和notify()/notifyAll()模式
在一个Lock当中,可以创建多个Condition实例(对象监视器),线程对象可以注册在指定的Condition中,从而可以有选择的进行线程通知,在调度线程上更加灵活
使用notify()/notifyAll()通知线程时,被通知的线程是有jvm随机选择的,但是使用 类ReentrantLock结合Condition对象可以实现选择性通知,这个功能非常重要,
而且Condition默认提供支持
而synchronized相当于整个lock对象中只有一个Condition实例,所有线程都注册在它身上。线程开始notifyAll时,需要通知所有wait线程,会有效率问题
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition
获取锁lock.lock(); //必须要获得锁
condition.await();
总结:condition使线程等待必须要先获得锁
4.正确使用Condition实现等待/通知
Object类中的wait()方法相当于Condition中的await()方法
Object类中的wait(long)方法相当于Condition中的await(long)方法
Object类中的notify()方法相当于Condition中的signal()方法
Object类中的notifyAll()方法相当于Condition中的signalAll()方法
5.使用多个Condition实现通知部分线程:错误用法
一个Condition signalAll会唤醒所有该Condition对应的await方法
6.使用多个Condition实现通知部分线程:正确用法
一个Condition signalAll方法对应一个Condition await方法
7.实现生产者/消费者模式:一对一交替打印
增加一个公共变量
实际就是本线程执行完改变条件停止本线程,通知其他线程执行
8.实现生产者/消费者模式:多对多交替打印
有可能出现假死问题,Condition需要signalAll处理
9.公平锁和非公平锁
lock锁分为公平锁和非公平锁
公平锁:线程获得锁的顺序必须按照线程加锁的顺序来分配的,即先来先得的锁,先进先出。
非公平锁:是一种获取锁的抢占机制,是随机获得锁,这种有可能导致某一个线程一直拿不到锁
注意:是线程加锁的顺序决定获得锁的顺序
线程开始执行就是加锁获得锁就是lock.lock();
ReentrantLock(true); true:公平锁
false:非公平锁
10.方法getHoldCount(),getQueueLength()和getWaitQueueLength()的测试
getHoldCount():查询当前线程保持此锁定的个数,也就是调用次数; 该线程lock数;
getQueueLength():获取正等待获取此锁定的线程的估计数; 还没有获得锁数;
getWaitQueueLength(Condition condition):返回等待与此锁定相关的给定条件Condition的线程估计数; 获得锁之后wait数;
11.方法hasQueuedThread(),hasQueuedThreads()和hasWaiters()的测试
hasQueuedThread(Thread thread):查询指定线程是否正在等待获取此锁定 是否有指定线程正在等待获取此锁定
hasQueuedThreads():查询是否有正在等待获取此锁定 是否有等待获取次锁定线程
hasWaiters(Condition condition):查询是否有线程正在等待与此锁定有关的condition条件 是否有wait数
12.方法isFair(),isHeldByCurrentThread()和isLock()的测试
isFair():是不是公平锁
isHeldByCurrentThread():当前线程是否保持锁定
isLock():查询此锁定是否由任意线程保持
13.方法lockInterruptibly(),tryLock()和tryLock(long timeout,TimeUnit unit)的测试。
lockInterruptibly():如果当前线程未被中断,则获取锁定,如果已经中断,者抛出异常
tryLock():仅在调用时锁定未被另一个线程保持的情况下获取锁
tryLock(long timeout,TimeUnit unit);如果锁定在给定时间段内没有被另外一个线程保持,或者当前线程未被中断,则获取锁
注:和lock.lock()一致,都是获取锁定,只是这个有条件获取
14.方法awaitUninterruptibly()的使用
和condition.await()方法一样,暂停线程,这个暂停线程之后调用interrupt()方法不会报错
15.方法awaitUntil()的使用
awaitUntil(Date deadline)暂停线程多久后自动唤醒,也可在时间到达之前被其它线程唤醒
16.使用Condition实现顺序执行
和一对一交替打印类似。
使用ReentrantReadWriteLock
类ReentrantLock具有完全互斥排他的效果,即同一时间只有一个线程在执行lock后面的任务,这样保证了实例变量的安全性,但是效率非常低
jdk中提供一种读写锁ReentrantReadWriteLock类,可以加快运行效率
1.类ReentrantReadWriteLock的使用:读读共享
private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
reentrantReadWriteLock.readLock().lock(); 获得锁
允许多线程同时执行lock()后面的方法
2.类ReentrantReadWriteLock的使用:写写互斥
reentrantReadWriteLock.writeLock().lock();
锁代码reentrantReadWriteLock.writeLock()同一时间只允许一个线程执行之后的代码
3.类ReentrantReadWriteLock的使用:读写互斥
4.类ReentrantReadWriteLock的使用:写读互斥
结论:只要操作中有写操作都是互斥的
下一篇: 2.工厂方法模式
推荐阅读
-
JavaEE基础day02 1.定义Java中的变量 四类八种 2.变量定义和使用的注意事项 3.数据类型的转换、强制数据类型转换4.算数运算符、比较运算符、逻辑运算符、赋值运算符、三元运算符
-
Java学习(五)——Java中的运算符
-
Shell中去除字符串里的空格或指定字符的方法
-
python try except 捕获所有异常的实例
-
Java入门五 常用的运算符
-
opencv提取旋转矩形区域的图像(将旋转矩形区域图像旋转成水平)
-
05. 数组的基本运算
-
asp.net core 使用 AccessControlHelper 控制访问权限
-
webpack3、4的基本的使用方法
-
Qt4.7中 默认的构造函数