synchronize在高并发领域可谓是元老级别了,博主最近整理了一下synchronize的用法,和简单的概念。
概念
对象锁:包括 方法锁(默认锁对象为this当前实例对象)和同步代码块锁(自己指定锁对象)
类锁:指synchronized 修饰静态的方法或指定锁对象为Class对象。
用法
同步代码块锁
用this锁:
自己指定锁:
用this时,2个线程用的是同一把锁,可以保证串行执行。自定义2把锁(lock1,lock2)时,由于是2个锁对象,无法保证2个线程串行执行。
方法锁
sysnchronized 修饰普通方法
可以保证串行执行
类锁
java类可能有很多个对象,但只有1个class对象,所以所谓的类锁其实就是Class对象锁而已。(不同实例只能在同一时刻被一个对象拥有)
sysnchronized加在static方法上
sysnchronized(*.class)代码块
均可实现代码的串行化执行
常见面试题
1.两个线程同时访问一个对象的同步方法
答案:可以实现串行化执行,因为用的是同一个对象锁,为同一把锁
2.两个线程访问的是两个对象的同步方法
答案:不可以实现串行化执行。因为锁对象不同,互不干扰。
3.两个线程访问的是synchronized的静态方法
答案:可以实现串行执行。因为synchronized加在静态方法上属于类锁,是同一个对象锁。
4.同时访问同步方法和非同步方法
答案:不可以实现串行执行。非同步方法不受影响。synchronized只作用的修饰的方法上。
5.访问同一个对象的不同的普通同步方法
答案:可以实现串行。因为同一个对象,默认使用的都是this对象,为同一把锁。
6、同时访问静态synchronized和非静态synchronized方案
答案:不可以实现串行。因为静态的锁对象为类锁,非静态的为实例的对象锁,2个锁对象不同,互不影响。
7.方法抛出异常后会释放锁吗?
答案:可以的。synchronized可以在抛异常后自动被释放。lock是需要手动释放的。
性质
可重入
指的是同一个线程的外层函数获得锁之后,内层函数可以直接再次获取该锁
好处:避免死锁,提升封装性
粒度:
1.同一个方法是可以重入的
2.可重入不要求是同一个方法
3.可重入不要求是同一个类
不可中断
sysnchronized一旦这个锁已经被别人获得了,如果我还想获得,我只能等待或者阻塞,直到别的线程释放这个锁。如果别人永远不释放锁,那么我只能永远的等下去。
相比之下: lock类可以拥有中断能力,第一点,如果我觉得我等的时间太长了,有权中断现在已经获取到锁的线程的执行。第二点,如果我觉得我等待的时间太长了不想再等了,也可以退出。
原理
查看monitor指令
通过反编译字节码查看原理
.java文件
反编译:
可重入原理(加锁次数计数器)
1.jvm 负责跟踪对象被加锁的次数
2.线程第一次给对象加锁的时候,计数变为1,每当这个相同的线程在此对象上再次获得锁时,计数会递增
3.每当任务离开时,计数递减,当技术为0时候,锁被完全释放
可见性原理
当被sysnchronized修饰之后的方法,在退出前会把数据刷新的主内存,当下个方法进入时候会从主存中拿到最新的数据
缺陷
效率低:锁对象释放的情况少,试图获得锁时不能设定超时,不能中断一个正在试图获得锁的线程(lock可以)
不够灵活:加锁和释放的时机单一,每个锁仅仅有单一的条件(某个对象),可能是不够的(lock可以)
无法知道是否成功的获取锁
使用注意点:
锁对象不能为空,作用域不宜过大,避免死锁
如何选择lock和synchronized关键字(避免出错为原则)
1.如果可以都不用,而是用java.util.current包中的工具类(countdownluch。。。等)
2.如果适用,就优先使用synchronized
3.只有有必要使用lock的特性的时候才使用lock