Java并发3
轻量级锁:如果一个有多个线程访问,但多线程访问的时间是错开的,没有竞争,那么可以使用轻量级锁来优化;
monitor:重量级锁;
正常我们使用synchronized时,没有竞争则是轻量级锁,当遇到竞争时,就会锁膨胀,变成重量级锁,一个对象拿到锁时,其他对象需要等待阻塞,使用monitor;
自旋优化:重量级锁竞争时,还可以使用自旋来进行优化,如果当前线程自选成功(即这时持锁线程已经退出了同步块,释放了锁),这时当前线程就可以避免阻塞。适用于多核cpu。自旋失败依旧会进行阻塞。
在ajva6之后自旋锁是自适应的,根据情况进行多自旋或少自选甚至不自旋;自选会占用cpu时间,单核cpu就是浪费,多核才能发挥优势;java7后不能控制是否开启自旋功能;
偏向锁:轻量级锁在没有竞争时(就自己这个线程),每次重入仍然需要CAS操作。java6中引入了偏向锁来做进一步优化;只有第一次使用CAS将线程ID设置到对象的Mark word头,之后每次看这个线程id是否是自己,发现是自己就没有竞争,就不用重新CAS。
可重入锁:就是一个对象中多个方法都加锁,且在调用某个加锁方法中接着调用其他加锁方法;
批量重偏向:现在有T1,T2两个线程,如果对象被多个线程访问,但是没有竞争,这时偏向了线程t1得对象仍有机会重新偏向T2,重偏向会重置对象的Tjread ID; 当撤销偏向锁阈值超过20次后(撤销后变成轻量级锁),jvm会觉得,是不是偏向错了,于是会给这些对象加锁时重新偏向至加锁线程;=
批量撤销:当撤销偏向锁阈值超过40次后,jvm会觉得自己确实偏向错了,根本就不该偏向,于是把整个类的所有对象都会变成不可偏向的,新建的对象也是不可偏向的。
锁消除:是对一些热代码,反复执行超过一点阈值后,使用JIT进行优化的加锁代码,对局部变量加锁的,永远不会有竞争时,就会把锁去消除掉,进而提升性能。
JIT即使编译器:当一些代码(热代码)反复执行,超过一点阈值,就会使用JIT即使编译器优化;当一个锁对某个局部变量加锁时,每次进来都是不用得局部变量加锁,JIT就会把synchronized给优化掉,相当于代码并没有使用synchronized;当两段代码执行,一个没有加锁,一个加锁了,两个都进行++操作,性能是差不多一致得,因为JIT进行了锁消除操作,进行了优化;也可以用一个命令来控制锁消除,默认是开启得,关闭锁消除后,加了锁得那段代码将不会被优化,性能会下降很多。
API 介绍
obj.wait() 让进入 object 监视器的线程到 waitSet 等待;wait可带参数,单位毫秒
obj.notify() 在 object 上正在 waitSet 等待的线程中挑一个唤醒
obj.notifyAll() 让 object 上正在 waitSet 等待的线程全部唤醒
sleep(long n) 和 wait(long n) 的区别
1) sleep 是 Thread 方法,而 wait 是 Object 的方法
2) sleep 不需要强制和 synchronized 配合使用,但 wait 需要和 synchronized 一起用
3) sleep 在睡眠的同时,不会释放对象锁的,但 wait 在等待的时候会释放对象锁
4) 它们状态 TIMED_WAITING
wait notify正确用法
synchronized(lock) {
while(条件不成立) {
lock.wait();
}
// 干活
}
//另一个线程
synchronized(lock) {
lock.notifyAll();
}
模式之保护性暂停
Guarded Suspension,用在一个线程等待另一个线程的执行结果;
有一个结果需要从一个线程传递到另一个线程,让他们关联同一个GuardedObject;
如果有结果不断从一个线程到另一个线程,那么可以使用消息队列(生产者/消费组)
JDK中,join的实现,Future的实现,就是此模式;
说白了就是创建一个公共的对象,一个往里面设置值,一个从里面取值;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构