https://mp.weixin.qq.com/s?__biz=MzI4NjI1OTI4Nw==&mid=2247489439&idx=1&sn=df404e70a8e55b4019317ef2036fbe7d&chksm=ebdef6a7dca97fb1e1a0dfd2eab194fa87f4971cd6b88645db072bcc9c98614b0ad30dc43399&scene=178&cur_album_id=1663134697297608707#rd
https://mp.weixin.qq.com/s/bJ3DSeXfW2h40I5u2C81BA
https://mp.weixin.qq.com/s/1PsHA8RbuMqLNHEdeHpUuQ
https://mp.weixin.qq.com/s/PbiGclcypbc38F411Xn4bQ
https://mp.weixin.qq.com/s/Gxqnf5vjyaI8eSYejm7zeQ
https://mp.weixin.qq.com/s/6kAMFCXT46mWfxRdega1vA
https://juejin.cn/post/6930237689870417927
https://juejin.cn/post/6934673900156485640
https://www.cnblogs.com/greta/p/5624839.html
http://ibruce.info/2013/12/19/how-to-stop-a-java-thread/
https://juejin.cn/post/6950933916245049351
Java并发——Synchronized关键字和锁升级,详细分析偏向锁和轻量级锁的升级_tongdanping的博客-CSDN博客
synchronized锁的是什么?说说对它的理解
修饰实例方法与对象时,需要获取的是实例对象的监视器锁。
修饰静态方法与class时,需要获取的是Class对象的监视器锁。
线程a访问实例对象的同步方法,线程b访问静态同步方法时,两者不互斥。
在JDK1.6以前,使用synchronized就只有一种方式即重量级锁,而在JDK1.6以后,引入了偏向锁,轻量级锁,重量级锁
线程是怎么知道某个对象是否被其他线程占有的?——通过对象头中的MarkWorld
在64位的虚拟机中:
为什么要有偏向锁?
大多数时候是不存在锁竞争的,常常是一个线程多次获得同一个锁,因此如果每次都要竞争锁会增大很多没有必要付出的代价,为了降低获取锁的代价,才引入的偏向锁。
线程获取到偏向锁的过程?
什么时候偏向锁升级为轻量级锁?
当有另外一个线程竞争获取这个锁时,由于该锁已经是偏向锁,当发现对象头 Mark Word 中的线程 ID 不是自己的线程 ID,就会进行 CAS 操作获取锁。
如果获取成功,直接替换 Mark Word 中的线程 ID 为自己的 ID,该锁会保持偏向锁状态;
如果获取锁失败,代表当前锁有一定的竞争,先进行偏向锁撤销,再将偏向锁将升级为轻量级锁。
偏向锁是怎么撤销的?
如果线程在全局安全点检查时,还需要执行同步方法,则先撤销偏向锁,再升级锁。如果线程已经执行完同步方法后,并有其他线程需要使用时,将偏向锁的拥有者切换为另外线程。
为什么要有轻量级锁?
轻量级锁考虑的是竞争锁对象的线程不多,而且线程持有锁的时间也不长的情景。因为阻塞线程需要CPU从用户态转到内核态,代价较大。因此考虑成用线程自旋代替阻塞。
轻量级锁什么时候升级为重量级锁?
自旋次数超过jvm最大自旋次数或者超过自适应次数
为什么要有重量级锁?
当线程竞争激烈时,大量线程自旋空转严重消耗cpu,自旋影响大于阻塞,那么这个时候轻量级锁就会膨胀为重量级锁。重量级锁把除了拥有锁的线程都阻塞,防止CPU空转。
重量级锁是怎么实现的?
当synchronized处于重量级锁时,MarkWorld存储了指向重量级监视器锁的指针,对象的监视器(monitor)锁对象由ObjectMonitor对象实现(C++),其数据结构如下:
ObjectMonitor() {
_count = 0; //用来记录该对象被线程获取锁的次数
_waiters = 0;
_recursions = 0; //锁的重入次数
_owner = NULL; //指向持有ObjectMonitor对象的线程
_WaitSet = NULL; //处于wait状态的线程,会被加入到_WaitSet
_WaitSetLock = 0 ;
_EntryList = NULL ; //处于等待锁block状态的线程,会被加入到该列表
}
线程在获取锁的几个状态的转换图:
那么Synchronized修饰的代码块/方法如何获取monitor对象的呢?——不管是方法同步还是代码块同步都是基于进入和退出monitor对象来实现
Synchronized代码块同步在需要同步的代码块开始的位置插入monitorenter指令,在同步结束的位置或者异常出现的位置插入monitorexit指令(一个方法可以被分成多个代码块,因此需要明确加锁的范围)
Synchronized方法同步是检查方法的ACC_SYNCHRONIZED标志,如果有这个标志,那么线程在执行方法前会先去获取对象的monitor对象,如果获取成功则执行方法代码,执行完毕后释放monitor对象,如果monitor对象已经被其它线程获取,那么当前线程被阻塞。
在JVM中monitorenter和monitorexit字节码依赖于底层的操作系统的Mutex Lock来实现的,但是由于使用Mutex Lock需要将当前线程挂起并从用户态切换到内核态(synchronized锁升级优化 - 知乎)来执行,这种切换的代价是非常昂贵的。
锁升级可逆吗?
为了避免无用的自旋,轻量级锁一旦膨胀为重量级锁就不会再降级为轻量级锁了;
偏向锁升级为轻量级锁也不能再降级为偏向锁。
一句话就是锁可以升级不可以降级,但是偏向锁状态可以被重置为无锁状态。
https://mp.weixin.qq.com/s/ts2Pjz3VpWm50kY-Ru7iTA
https://mp.weixin.qq.com/s?__biz=MzU4NzA3MTc5Mg==&mid=2247483980&idx=1&sn=c9b620834adb889ad8ccedb6afdcaed1&chksm=fdf0ea13ca8763058e59bde10f752264a5de6fb9dd087ca2a4290f90da4b2c2e78407613c5cd&scene=178&cur_album_id=1657204970858872832#rd
https://mp.weixin.qq.com/s?__biz=MzUxODAzNDg4NQ==&mid=2247487236&idx=2&sn=1475f0250734b8ec2ee7bda4905b3b05&scene=21#wechat_redirect
https://juejin.cn/post/6844904191375179784
https://juejin.cn/post/6924276177276239879#heading-11
https://mp.weixin.qq.com/s?__biz=MzU0OTk3ODQ3Ng==&mid=2247485084&idx=1&sn=fc11d4574221fbe70b5f543adf83a82c&chksm=fba6ee9fccd16789b476725b2478219bd803c156eeb50c0fe34c92785212238902ef0ece7466&scene=21#wechat_redirect
https://mp.weixin.qq.com/s?__biz=MzkxNTE3NjQ3MA==&mid=2247488192&idx=1&sn=85fa12be29fef85d41c571b2c853de5d&scene=21#wechat_redirect
https://mp.weixin.qq.com/s/SUzNj4MsRJJzkhiquuLy0Q
https://mp.weixin.qq.com/s/xtVKp9fUoIs8d94-5P2pEA
https://mp.weixin.qq.com/s/OKTW_mZnNJcRBrIFHONR3g
https://mp.weixin.qq.com/s?__biz=MzU4NzA3MTc5Mg==&mid=2247484036&idx=1&sn=75e9e93a82a811e9c71b8127cf7ac677&chksm=fdf0eadbca8763cd7ab74757f9472d061c0244d2373a1ea85b1cbc833941441fdb1e91ead5b4&scene=178&cur_album_id=1657204970858872832#rd
https://blog.csdn.net/nrsc272420199/article/details/106085365
https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html
https://mp.weixin.qq.com/s/EhBt44Rj0c5E-UVf742aGw
https://mp.weixin.qq.com/s/e1slhQ7qMWeLGzJbeImywQ
https://mp.weixin.qq.com/s/KHSi0M4sIN-rBbpAKfnBNw
https://juejin.cn/post/6925258524096200718
https://mp.weixin.qq.com/s/Qpdxfal-m0KOUxLeMJlPxw
https://mp.weixin.qq.com/s?__biz=MzUxODAzNDg4NQ==&mid=2247487264&idx=2&sn=4bb89d3691e449469eca86eb71828feb&scene=21#wechat_redirect
https://mp.weixin.qq.com/s/0KGNDELlrfhTmvzdUz0bIg
https://mp.weixin.qq.com/s/Pclus98-FOEVZE3p3AGGKw
https://mp.weixin.qq.com/s?__biz=MzU4NzA3MTc5Mg==&mid=2247484118&idx=1&sn=9526a1dc0d42926dd9bcccfc55e6abc2&chksm=fdf0ea89ca87639f3ecadc523c4d80970e05d0731fcf65c80439a71d553b44cfb767ae683af3&scene=178&cur_album_id=1657204970858872832#rd
https://blog.csdn.net/qq_33591903/article/details/97790015
https://blog.csdn.net/qq_33591903/article/details/106736396
https://juejin.cn/post/6844904165383110664
https://mp.weixin.qq.com/s/wABcn9euUVxJKLsSgJYR3Q
https://mp.weixin.qq.com/s/EIBxpgHOjWrCBl3xjS6OLQ
https://mp.weixin.qq.com/s/By6XM7QChuxSWH-U-7YbzQ
https://juejin.cn/post/6876681462712631303
https://mp.weixin.qq.com/s/DiEftiV_kTOlR4YmD4pggg
volatile的特性,保证可见性与禁止指令重排序,但不能保证原子性
(1)如何保证可见性?
先谈谈JMM,即java内存模型
背景:处理器与内存的处理速度相差很大,因此在处理器与内存之间加入了高速缓存,带来了缓存一致性问题。
JMM的规定
所有的共享变量都存储于主内存,这里所说的变量指的是实例变量和类变量,不包含局部变量,因为局部变量是线程私有的,因此不存在竞争问题。
每一个线程还存在自己的工作内存,线程的工作内存,保留了被线程使用的变量的副本。
线程对变量的读,取都必须在工作内存中完成,而不能直接读写主内存中的变量。
不同线程之间也不能直接访问对方工作内存中的变量,线程间变量的值的传递需要通过主内存中转来完成。
被volatile修饰的变量,当线程a在自己的工作内存中修改了这个变量时,将会同步到主内存中,并让其他线程立即看到这个变量的最新值。
其他线程怎么立即感受到共享变量的变化的?
通过缓存一致性协议MESI
协议内容——当CPU写数据时,如果发现操作的变量是共享变量,即在其他CPU中也存在该变量的副本,会发出信号通知其他CPU将该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,发现自己缓存中缓存该变量的缓存行是无效的,那么它就会从内存重新读取。
每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存里。
不停的嗅探会导致什么问题?
导致总线风暴——不停的从主内存嗅探,无效的交互会导致总线带宽达到峰值。
(2)如何禁止指令重排序的?
为什么会有指令重排序?
为了提高性能,编译器和处理器常常会对既定的代码执行顺序进行指令重排序。
但不管怎么重排序,单线程下的执行结果不能被改变——这就是as-if-serial语义
编译器在生成指令的时候,在volatile修饰的变量的操作前或后加上内存屏障来禁止指令重排序的。
https://mp.weixin.qq.com/s?__biz=MzU0OTk3ODQ3Ng==&mid=2247484058&idx=1&sn=d5c1533204ea655e65947ec57f924799&chksm=fba6ea99ccd1638f945c585cf3b2df6f4d4112b17ea3648730d50fdb5508555d5f30316f4186&scene=21#wechat_redirect
AQS主要是采用state,通过对state的CAS判断来获取锁和解锁,并且存在等待队列和条件等待队列来park相关线程之后入队等待,有公平和非公平两者模式来唤醒等待的线程。
为什么需要个AQS
我:主要是为了封装和抽象,通过封装了公共的方法,减少重复代码。
https://mp.weixin.qq.com/s/1Nq_izUkOGmtvkIQ9c0QRQ
https://mp.weixin.qq.com/s/5bEQMmj7KAy2olIbBVZa9A
https://mp.weixin.qq.com/s?__biz=MzU4NzA3MTc5Mg==&mid=2247484035&idx=1&sn=ccaec352e192f1fd40020d9a984e9461&chksm=fdf0eadcca8763ca5c44bd19118fd00e843c163deb40cda444b3fc08430c57760db15eca1ea6&scene=178&cur_album_id=1657204970858872832#rd
https://mp.weixin.qq.com/s?__biz=MzU0OTk3ODQ3Ng==&mid=2247484094&idx=1&sn=b337161f934b1c27ff1f059350ef5e65&chksm=fba6eabdccd163abc8978b65e155d79a133f20ee8a5bff79a33ed20a050c2bd576581db69fe6&scene=21#wechat_redirect
https://tech.meituan.com/2019/12/05/aqs-theory-and-apply.html
https://mp.weixin.qq.com/s/Y4GbMdNmSDvHtomxtObRSg
https://mp.weixin.qq.com/s/ks1-_tsTdWm1FEux42rgZw
https://mp.weixin.qq.com/s/gC8Uj8otLGnOKN6ryb1uZQ
https://segmentfault.com/a/1190000017372067
https://segmentfault.com/a/1190000014102756
https://juejin.cn/post/6844904169619324941
https://mp.weixin.qq.com/s?__biz=MzIxMjE5MTE1Nw==&mid=2653192625&idx=1&sn=cbabbd806e4874e8793332724ca9d454&chksm=8c99f36bbbee7a7d169581dedbe09658d0b0edb62d2cbc9ba4c40f706cb678c7d8c768afb666&scene=21#wechat_redirect
https://mp.weixin.qq.com/s?__biz=MzIxMjE5MTE1Nw==&mid=2653192736&idx=1&sn=24d4054b062e28db9e54c735aafe2407&chksm=8c99f0fabbee79ecfd9198aa89bc78084e9b7db056078982975d8910c12b5d3dd1d16c2509c3&scene=21#wechat_redirect
https://mp.weixin.qq.com/s?__biz=MzU4NzA3MTc5Mg==&mid=2247483977&idx=1&sn=1a3aa3aec27073aa3b422bc41d7fbe2d&chksm=fdf0ea16ca8763005aff64834eeb7bef08bf4ee2d8febb7e8d4d8e5d1542336e13fac71e2881&scene=178&cur_album_id=1657204970858872832#rd
https://mp.weixin.qq.com/s/GR7lLGp9JH4bsAgQB3uLrw
https://mp.weixin.qq.com/s?__biz=MzU0OTk3ODQ3Ng==&mid=2247484070&idx=1&sn=c1d49bce3c9da7fcc7e057d858e21d69&chksm=fba6eaa5ccd163b3a935303f10a54a38f15f3c8364c7c1d489f0b1aa1b2ef293a35c565d2fda&scene=21#wechat_redirect
https://juejin.cn/post/6935815791329673253
Java线程的6种状态及切换(透彻讲解)_潘建南的博客-CSDN博客_线程状态
JDK的Thread源码中,将线程的状态分为6种:
注意点:
(1)synchronized为关键字,lock为一个接口
(2)synchronized可作用与实例对象、类、方法上,lock作用于Lock对象上
(3)synchronized:执行完同步方法释放锁或出现异常由jvm自动释放锁;lock必须手动加锁解锁,需要在finally中手动释放锁
(4)synchronized不可以判断是否成功获取锁,而lock可以(通过tryLock())
(5)都是可重入锁
synchronized
lock通过对aqs中的state字段做加1减1的操作来实现可重入的
(6)synchronized为非公平锁,而lock的实现类ReentranLock(默认为非公平锁)可以指定公平性
ReentrantLock 在遇到竞争时有公平和非公平两种处理模式,在创建对象时可以指定。
当线程要获取锁失败时,会将线程添加到一个由链表实现的队列尾部,依次选取队列头部的线程运行。
非公平模式下,在还未将新来的线程添加到尾部时,如果当前没有正在运行的线程,就直接插队运行新线程了。
(7)synchronized为不可中断锁,而lock为可中断锁
(8)资源竞争不激烈,synchronized的性能优于ReetrantLock。资源竞争很激烈,synchronized的性能远低于ReetrantLock,且synchronized锁升级不可逆
https://mp.weixin.qq.com/s?__biz=MzU0OTk3ODQ3Ng==&mid=2247484095&idx=1&sn=aa915ae16d0a550bbe7ae4b6fec99173&chksm=fba6eabcccd163aa2bc0e880d7d3929eee5ff834a73a6ccc3a53237537a4555ef7fd4d9e70d0&scene=21#wechat_redirect
线程死锁
产生死锁的条件有四个:
互斥条件:所谓互斥就是进程在某一时间内独占资源。
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
线程死锁是因为多线程访问共享资源,由于访问的顺序不当所造成的,通常是一个线程锁定了一个资源A,而又想去锁定资源B;在另一个线程中,锁定了资源B,而又想去锁定资源A以完成自身的操作,两个线程都想得到对方的资源,而不愿释放自己的资源,造成两个线程都在等待,而无法执行的情况。
要解决死锁,可以从死锁的四个条件出发,只要破坏了一个必要条件,那么我们的死锁就解决了。在java中使用多线程的时候一定要考虑是否有死锁的问题哦。
https://mp.weixin.qq.com/s?__biz=MzI4NjI1OTI4Nw==&mid=2247489439&idx=1&sn=df404e70a8e55b4019317ef2036fbe7d&chksm=ebdef6a7dca97fb1e1a0dfd2eab194fa87f4971cd6b88645db072bcc9c98614b0ad30dc43399&scene=178&cur_album_id=1663134697297608707#rd
https://tech.meituan.com/2018/11/15/java-lock.html
https://mp.weixin.qq.com/s?__biz=MzkxNTE3NjQ3MA==&mid=2247485739&idx=1&sn=801792f4987c4c3bd3d976d030476113&chksm=c1626452f615ed441749a6dd8e3e1e4d73187247b12824e968093c1fa1f950a90b8e7d428729&token=1260092512&lang=zh_CN#rd
https://mp.weixin.qq.com/s/dwpTgeVXyH9F7-dklk7Iag
https://mp.weixin.qq.com/s?__biz=MzkzNTEwOTAxMA==&mid=2247485078&idx=1&sn=8357c498fab66b8c6be4f030ed41226a&chksm=c2b24e6bf5c5c77d24341053d8b0f8d5ed40b7432498ac8891eff6f406955f7b92bfbd633c1a&scene=178&cur_album_id=1512519209967271939#rd
https://zhuanlan.zhihu.com/p/95835099
https://blog.csdn.net/qq_39241239/article/details/87030142
https://mp.weixin.qq.com/s?__biz=MzU4NzA3MTc5Mg==&mid=2247484363&idx=1&sn=743dcdfb84f83cfc38882407f87c7c6d&chksm=fdf0eb94ca87628296d86d16769f25e10acd052bcd78f4a4608f4218e4948aff610b04a41f60&scene=178&cur_album_id=1657204970858872832#rd
https://zhuanlan.zhihu.com/p/98593407
https://blog.csdn.net/qq_33591903/article/details/106282228
https://mp.weixin.qq.com/s?__biz=MzU0OTk3ODQ3Ng==&mid=2247485156&idx=1&sn=94ab9f77ca3b04c11f666e207616b824&chksm=fba6eee7ccd167f1381783fc28d44bf9ee4eb92617862be23321ffecca32396fa7e3a99c960a&scene=21#wechat_redirect
https://tech.meituan.com/2019/02/14/talk-about-java-magic-class-unsafe.html
https://juejin.cn/post/6844904191219990535#heading-3
https://mp.weixin.qq.com/s?__biz=MzU0OTk3ODQ3Ng==&mid=2247484129&idx=1&sn=d2a95310db5751b152ba070caee4ebae&chksm=fba6eae2ccd163f48aef9d98a4dbb55d578a24af710e1436cc876fe3119b03135532e16d80bc&scene=21#wechat_redirect