JAVA并发之synchronized
synchronized
synchronized
首先synchronized是jdk提供的内置锁,既然是锁那就具有互斥性和可见性,可保证在多线程竞争资源时不会出现并发问题
synchronized用法
根据修饰对象分类
-
同步方法
-
同步静态方法
public synchronized void method(){ //逻辑代码 }
-
同步非静态方法
public synchronized static void method(){ //逻辑代码 }
-
-
同步代码块
synchronized(object) {}
根据获取的锁分类
在 Java 中,每个对象都会有一个 monitor 对象,这个对象其实就是 Java 对象的锁 ,因为类对象本来也是一个对象,所以每个类也有一个类锁。
当某一线程占有这个monitor对象的时候,先看monitor计数器是不是0,如果是0,说明还没有线程占用,这时候该线程占有这个锁,并且计数器+1;如果计数器不是0,看当前占有锁的线程是不是本线程,如果是本线程就+1,这就是可重入的概念;如果当前计数器不是0也不是当前线程占有,则进去阻塞状态。
-
对象锁
-
类锁
synchronized原理分析
代码块加锁的实现是通过monitorEnter 和monitorExit来实现的,通过javap 反编译class文件你会发现synchronized所包含的代码前面和后面分别加了monitorEnter 和monitorExit,其中有两个monitorExit,第一个是正常解锁时执行的,第二个是异常时用来释放锁的。
image.png对方法加锁的实现是通过标志位ACC_SYNCHRONIZED来实现的
image.pngJAVA虚拟机对synchronized的优化
在jdk1.6以前synchronized是一个重量级锁,1.6及以后将它优化为无锁,偏向锁,轻量级锁,重量级锁
偏向锁: 在对象第一次被某一线程占有的时候 ,将线程号写入,下一个线程再次访问时,发现线程号是当前占用线程号,直接成功,否则升级为轻量级锁
轻量级锁:是一个自旋锁,通过cas自旋来获取锁,超过一定次数升级为重量级锁
重量级锁:通过互斥量来实现,性能比较低
synchronized是一个非公平锁
moniter 对象中有两个集合 _EntryList, _WaitSet 当线程阻塞的时阻塞线程会进入_EntryList,等待count为0重新调用,当线程调用了wait方法是线程会阻塞进入_WaitSet中 等待notify唤醒 ,无论是哪种情况 当一个新的线程进来同时count 为0 是 都不能保证新的线程在_EntryList或者_WaitSet 中先执行其中线程