浅谈synchronized
1.什么是synchronized
- synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。它包括两种用法:synchronized 方法和 synchronized 块。
2.synchronized怎么用
- synchronized主要有两种用法:修饰方法和修饰代码块
//同步非静态方法
public synchronized void staticMethod() {
......
}
//同步静态方法
public synchronized static void noStaticMethod() {
......
}
/**
* 同步代码块
* @param this|object 或 类.class
*/
//this|object用法
private final Object codeBlock =new Object();
Public void methodName(){
Synchronized(codeBlock){
……
}
}
//类.class用法
public static void method() {
synchronized(SyncThread.class) {
......
}
}
3.synchronized原理
-
synchronized是利用锁的机制来实现同步的。
锁机制有如下两种特性:
互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机制,这样在同一时间只有一个线程对需同步的代码块(复合操作)进行访问。互斥性我们也往往称为操作的原子性。
可见性:必须确保在锁被释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程是可见的(即在获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作从而引起不一致。 -
查看线程运行情况:有兴趣可以找jdk/bin下的jconsole工具使用,配合Jstack pid命令能找出线程具体状态(新建(NEW)、可运行(RUNNABLE)、运行(RUNNING)、阻塞(BLOCKED)、死亡(DEAD))
-
JVM指令分析
通过Javap -V进行反编译:
:代码块的加锁monitorenter和monitorExit配合使用。
:对方法的加锁ACC_SYNCHRONIZED
4.Java虚拟机对Synchronized的优化
- JDK1.6以前都是为重量级锁,JDK1.6之后,出现了偏向锁、轻量级锁、重量级锁。
- 偏向锁:在对象第一次被某一线程占有的时候,是否偏向锁置1,锁表01,写入线程号,当其他的线 程访问的时候,竞争若失败后转为轻量级锁(CAS算法),很多次被第一次占有它的线程获取次数多成功,无锁状态时间非常接近,竞争不激烈的时候适用
- 轻量级锁:线程有交替适用,互斥性不是很强,CAS失败
- 重量级锁:强互斥,等待时间长
- 自旋锁:竞争失败的时候,不是马上转化级别,因为用户线程转为核心线程消耗时间更大,所以执行几次空循环。
- 锁消除:JIT在编译的时候吧不必要的锁去掉
锁的存在于实力对象的对象头,一个实例对象包括对象头、实例变量、填充数据。对象头是加锁的基础。通过对对象头的对应位置进行更改,能将锁进行转化级别。但是只能升级,不能降级
创作不易,转载请注明出处!