Synchronized三种使用场景
1.修饰实例方法:锁作用于当前对象的实例,因此程序进入同步代码方法前要获取到当前对象实例的锁。
2.修饰静态方法:给当前的类加锁,作用于当前类的所有对象实例,进入同步代码前要获得当前class的锁。因为静态成员不属于任何一个是咧对象,是类成员。(访问静态Synchronized方法占用的锁是当前类的锁,访问非静态synchronized方法所占用的锁是当前实例对象的锁)
3.修饰代码块:指定加锁对象,对给定对象加锁。
synchronized(this/object) ---->要获得给定对象锁
sychronized(类.class)----->要获得当前class的锁
Synchronized和ReendtrantLock的区别
1.两者都是“可重入锁”
2.synchronized依赖于JVM;ReendtrantLock依赖于JDK API(因此ReendtrantLock需要lock()和unlock()方法配合try/finally语句来完成)
3.ReendtrantLock增加了一些高级功能
- 等待可中断:lock.lockInterruptibly()
- 可实现公平锁:通过构造方法
- 可实现选择性通知
拓展1(双重校验锁实现对象单列创建-线程安全)
public class Singleton{ private volatile static Singleton singleton; //volatile 禁止JVM指令重排 private Singleton(){} public static Singleton getInstance(){ if (singleton==null){//判断是否已经实例化过了 synchronized (Singleton.class){//给类对象加锁 if (singleton==null){ singleton = new Singleton(); } } } return singleton; } }
拓展2(AQS-AbstractQueuedSychronizer)
AQS是用来构建锁和同步器的框架,位于java.util.concurrent.locks包下
核心思想:如果被请求的资源空闲,将其线程设置为有效的工作线程,并将共享资源设为锁定状态,如果被请求的资源被占用,则需要一套线程阻塞等待以及被唤醒时锁分配的机制;AQS用CLH队列锁实现,将暂时获取不到锁的线程加入到队列中