Synchronized

多线程操作共享数据,加锁保证访问共享数据的线程安全性

三种加锁

1、静态方法,类对象

2、非静态方法,当前对象-this

3、代码块,指定对象-lock

释放锁

1、代码执行完毕

2、异常结束

非公平锁

预防饥饿

底层源码实现

代码块加锁,通过monitorenter、monitorexit指令实现

静态方法、方法加锁,通过在方法的flags中加入ACC_SYNCHRONIZED实现

如何保证线程安全

1、原子性,互斥锁monitorenter、monitorexit、ACC_SYNCHRONIZED

2、有序性,通过Acquire屏障、Release屏障保证代码块内部重排

3、可见性,进入synchronized代码块时,从主内存获取变量,退出时刷新到主内存

monitorexit指令出现2次

正常退出、异常退出

可重入原理

获取锁时,检查锁状态,为0表示没有被占用,每一次进入方法,status加1

释放锁时,每一次退出方法,status减1

避免死锁

并发时,感觉前面的代码在后面执行

as-if-serial语义,指编译器、处理器无论如何优化,单线程执行结果不变

自旋锁

尝试获取锁的线程不会立即阻塞,循环获取锁

提升synchronized并发性能

1、减少锁竞争

2、减少锁粒度

3、减少锁时间

注意点

1、锁对象不能为null

2、作用域不能过大,影响性能

3、避免死锁

缺点

1、不能设置锁超时时间

2、不能通过代码释放锁

3、容易死锁

lock

1、资源竞争激烈,lock性能更好

2、手动释放锁

3、只能写在代码里

ReentrantLock

1、synchronized依赖JVM,ReentrantLock依赖API

2、ReentrantLock功能:等待可中断、公平锁、锁绑定条件

浙ICP备11005866号-12