一、为什么使用synchronized
synchronized是Java中的关键字,主要解决并发编程中的安全问题,多线程操作共享数据时,可以保证在同一时刻只有一个线程可以执行synchronized修饰的方法或代码块,同时保证共享数据的可见性。
1.synchronized的使用方式
(1)修饰方法
- 实例方法,锁的对象是实例对象
// 实例方法,锁的对象是该类的实例对象
public synchronized void method() {} - 静态方法,锁的对象是类对象
// 静态方法,锁的对象是类对象
public static synchronized void method() {}
(2)修饰代码块
- 实例对象,锁的对象是类的实例对象
synchronized(this) {} - 类对象,锁的对象是类对象
synchronized(Test.class) {} - 任意实例对象object,锁的对象是实例对象object
String lock = "";
synchronized(lock) {}
二、synchronized的原理
1.synchronized对象锁机制
synchronized是基于对象锁(monitor)机制实现的,使用synchronized关键字时,锁的对象实际是获取对象的monitor,只有获取到对象的monitor才能继续向下执行,否则只能等待,即同一时刻只有一个线程能获取到对象的monitor,执行同步代码块时,首先要执行monitorenter指令,退出的时候执行monitorexit指令。
在有synchronized修饰的方法A中调用另一个同步方法B,同一个线程在执行方法A时执行获取锁的指令monitorenter,在执行方法B时不需要重新获取锁,只有monitorexit指令,这就是锁的重入性,每个对象拥有一个计数器,当线程获取该对象锁后,计数器就会加一,释放锁后就会将计数器减一。
2.synchronized的happens-before规则
即synchronized的对同一个监视器的解锁happens-before于对该监视器的加锁。
三、synchronized的特点和缺点
1.synchronized的特点
- 可重入性:同一线程的外层方法获得锁后,内层方法可以不需要重新竞争获取该锁,可以直接获取该锁;
- 不可中断性:一旦锁被某个线程获取,其他线程只能等待或阻塞,直到别的线程释放这个锁。
2.synchronized的缺点
- 效率低
- 释放锁的情况少,如遇到等待IO和其他原因阻塞,只有程序正常执行完或抛出异常时方能释放锁;
- 试图获取锁时不能设置超时;
- 不能中断一个正在获取锁的线程;
- 如果多个线程进行读操作时,当一个线程获取锁进行读操作时,其他线程只能等待,无法进行读操作
- 无法知道是否成功获取锁