锁的类型
对象锁
-
同步代码块锁,所有的实例化对象各自带有一把锁(this)
sychronized(this) { }
-
普通方法上带有synchronized修饰,默认使用本对象作为锁
public synchronized void test() { }
类锁
-
静态方法锁(使用class唯一对象作为锁)
public static synchronized test() { }
-
同步代码块,锁对象为.class对象
synchronized(xxx.class) { }
多线程访问同步锁的七种情况
-
两个线程同时访问一个同步对象的同步方法
答:串行执行方法,两个线程依次拿到当前同步方法的锁。
-
两个线程访问的是两个对象的同步方法
答:分情况:如果两个对象使用的是类锁,那么是串行执行方法,如果两个对象的方法使用的是当前对象锁,那么并行执行方法。
-
两个线程访问的是synchronized的静态方法
答:串行执行方法,由于是synchronized修饰的静态方法默认实现类锁,所有多线程执行为串行。
-
同时访问同步方法和非同步方法
答:并行执行方法,由于非同步方法不受同步方法的限制,所以多线程执行方法的时候不会受到锁的影响。
-
同时访问一个对象的不同的普通同步方法
答:串行执行方法,由于普通的同步方法默认使用本对象为锁,在者这里多线程访问的是同一个对象,所以锁是相同的,所以会串行执行方法。
-
同时访问静态synchronized和非静态的synchronized方法
答: 并行执行方法,由于静态的synchronized使用本类作为锁,而非静态的synchronized使用本对象作为锁,锁不同,多线程执行的时候不会相互受到影响,所以并行执行方法。
-
方法抛出异常后会释放锁。
七种情况总结,3点核心思想
- 一把锁同时只能被一个线程获取,没有拿到锁的线程必须等待。
- 每个实例都应有自己的一把锁,不同实例之间互不影响;锁对象是*.class或者synchronized修饰的是static静态方法的时候,所有对象共用一把锁。
- 无论是方法正常结束或者抛出异常,都会释放锁。
使用注意点
- 锁对象不能为空。
- 作用域不宜过大。
- 避免死锁。
如何选择Lock和synchronized关键字
- 在程序中如果能不使用同步,就劲量不使用这两个关键字,优先选择java.util.concurrent包下的类。
- 能用synchronized解决的方法就劲量选择synchronized
- 如果需要Lock独有的特性的时候,才使用Lock.
网友评论