synchronized发生异常会自动释放锁
在 Java 早期版本中,synchronized属于重量级锁,效率低下,因为监视器锁(monitor)是依赖于底层的操作系统的 Mutex Lock 来实现的,Java 的线程是映射到操作系统的原生线程之上的互斥锁来实现的。如果要挂起或者唤醒一个线程,都需要操作系统帮忙完成,而操作系统实现线程之间的切换时需要从用户态转换到内核态,这个状态之间的转换需要相对比较长的时间,时间成本相对较高,这也是为什么早期的 synchronized 效率低的原因。庆幸的是在 Java 6 之后 Java 官方对从 JVM 层面对synchronized 较大优化,所以现在的 synchronized 锁效率也优化得很不错了。JDK1.6对锁的实现引入了大量的优化,如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销。
使用方式
- 修饰实例方法方法: 作用于当前对象实例加锁,进入同步代码前要获得当前对象实例的锁。synchronized(this)。
- **修饰静态方法: ** 也就是给当前类加锁,会作用于类的所有对象实例。
因为静态成员不属于任何一个实例对象,是类成员( static 表明这是该类的一个静态资源,不管new了多少个对象,只有一份)。所以如果一个线程A调用一个实例对象的非静态 synchronized 方法,而线程B需要调用这个实例对象所属类的静态 synchronized 方法,是允许的,不会发生互斥现象,因为访问静态 synchronized 方法占用的锁是当前类的锁,而访问非静态 synchronized 方法占用的锁是当前实例对象锁。 - **修饰代码块: ** 指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。最好别用字符串,因为JVM中,字符串常量池具有缓存功能。
双重校验锁实现对象单例(线程安全):
通过volatile保证线程的可见性并防止指令的重新排序,synchronized加锁防止重复实例化。
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton