synchronize会使用,可是对于深层次的知识,不是很清楚,故整理一篇博客。java
简介:安全
可以保证在同一时刻,最多只有一个线程执行该端代码,以达到保证并发安全效果。并发
两种用法:性能
包括方法锁(默认锁对象为this当前实例对象) 锁某个方法
同步代码块锁(本身制定锁对象) 锁某块代码
指synchronized修饰静态的方法或指定锁为Class对象
概念: Java类可能有不少个对象,但只有一个Class对象。优化
本质: 所谓的类锁,不过是Class对象的锁而已。this
对线程访问同步方法的7种状况:操作系统
1. 两个线程同时访问一个对象的同步方法线程
2. 两个线程访问的是两个对象的同步方法调试
3. 两个线程访问的是synchronized的静态方法: 静态方法带synchronizedcode
4. 同时访问同步方法和非同步方法,非同步方法不受影响
5. 访问同一个对象的不一样的普通同步方法
6. 同时访问静态synchronized和非静态synchronized方法
7. 方法抛异常后,会释放锁
小结核心:
1. 一把锁只能同时被一个线程获取,没有拿到锁的线程必须等待(1,5状况)
2. 每一个实例都对应有本身的一把锁,不一样实例之间互不影响。例如: 锁对象是.class以及synchronized修饰的是static方法的时候,全部对象共用同一把锁(对应第2,3,4,6状况)
3. 不管是方法正常执行完毕或者方法抛出异常,都会释放锁(7状况)
synchronize性质:
原理:
调试方法:
能够看到线层的状态:
原理:
加锁和释放锁的原理:
现象: 每个类的实例对应一把锁,每个synchronized方法都必须得到调用该方法的实例的锁才能够执行,不然阻塞。
咱们指定对象就能够了,锁的释放获取由JVM去自动实现。
获取和释放锁的时机: 内置锁
每个Java对象均可以用做实现一个同步的锁,这个锁称之为内置锁(监视器锁)。线程在家进入代码块以前,会自动获取这个锁。退出代码块时候会自动释放锁。
得到这个内置锁的惟一途径,就是进入到这个锁保护的代码块或者方法中。
加锁和释放锁的原理: 深刻JVM
每个对象都有个对象头,能够存储不少信息。
Monditorenter 和 Monditorexit指令
(联想操做系统知识:临界区)
每一个对象都与Monitor相关联,而一个Monitor的lock锁只能被一个线程同一时间得到。
一个线程尝试得到与这个对象关联的Monitor全部权到时候,只会发生如下三种:
1. Monitor计数器为0,目前尚未被得到,线程获取后计数器加1.
2. 若是Monitor已经拿到了锁的全部权,又重入了。这样致使计数器累加。
3. 若是Monitor已经被其余线程持有了。我去获取时候,只能阻塞状态了。知道技术器变为0,再去尝试获取锁。
关于Monditorexit:
释放对于Monitor的全部权,释放过程就是将Monitor计数器减1.若是减完是0,当前线程再也不拥有对Monitor的全部权了,其余的阻塞线程会再次尝试获取对该把锁的全部权,不是0这是可重入进来的,能够继续持有这把锁。
可重入原理: 加锁次数计数器
JVM负责跟踪对象被加锁的次数。每一个对象都含有一把锁,JVM负责跟踪对象被加锁的次数。
线程第一次给对象加锁的时候,技术变为1.每当这个相同的线程在此对象上再次得到锁时,计数会递增。
每当任务离开时候,技术递减,当计数为0到时候,锁被彻底释放。
synchronized缺陷:
效率低: 锁的释放状况少,视图得到锁时候不能设置超时,不能中断一个正在试图得到锁的线程。
不够灵活(读写锁更灵活): 加锁和释放的时机单一,每一个锁仅有单一的条件(某个对象),可能不够 。
没法知道是否成功获取到锁
反编译: javap -verbose xx.class
问题总结:
1. 使用注意点:
锁对象不能为空(锁信息保存在头部,对象都没有,怎么玩儿),做用域不宜过大(包裹的代码块),避免死锁。
2. 如何选择Lock和synchronized关键字
思考:
1. 多个线程等待同一个synchronized锁的时候,JVM如何选择下一个获取锁的是哪一个线程?
等待时间最长,随机?
2. Synchronized使得同时只有一个线程能够执行,性能较差,有什么办法能够提高性能?
优化使用范围
使用其它类型的锁,读写锁
3. 我想更灵活的控制锁的获取和释放(如今释放锁的时机都规定死了),怎么办?
本身实现lock接口,可控
4. 什么是锁的升级,降级。什么是JVM里的偏向锁,轻量级锁,重量级锁?
以前的版本中synchronized性能不是很好,通过后面的迭代。利用偏斜锁,轻量级锁,重量级锁。JVM根据synchronized关键字锁使用的次数和种种指标来对锁进行很是有效的优化。还涉及到对象头里面的一些字段。
总结:
JVM会自动经过使用monitor来加锁和解锁,保证了同时只有一个线程能够执行指定代码,从而保证了线程安全,同时具备可重入和不可中断性质。
MonitorEnter表示进入对象的监视器当中