简介
本文介绍Java的synchronized的对比,包括:synchronized与volatile的区别,synchronized与Lock的区别,synchronized与ReentrantLock的区别。
synchronized与volatile
项 | synchronized | volatile |
作用 | 锁定当前对象,只有当前线程可以访问该对象,其他线程被阻塞。 | 本质是在告诉 jvm 当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; |
使用范围 | 变量、方法、和类 | 变量 |
线程安全 | 可以保证变量的可见性和原子性 | 仅能实现变量的可见性,不能保证原子性 |
阻塞 | 可能会造成线程的阻塞 | 不会造成线程的阻塞 |
优化 | 标记的变量可以被编译器优化 | 标记的变量不会被编译器优化 |
synchronized与Lock
项 | synchronized | Lock |
存在层面 | java 内置关键字,在 jvm 层面 | java 类(实际是一个接口),在API层面 |
锁的释放 | 会自动释放锁: 线程执行完同步代码会释放锁 ; 线程执行中发生异常会释放锁 | 需在 finally 中手工释放锁(unlock()方法释放锁) |
锁的获取 | 若线程 1 获得锁,线程 2 等待; 若线程 1 阻塞,线程 2 会一直等待 | 分情况而定,Lock有多个获得锁的方式。 可尝试获得锁(tryLock()),线程可以不用一直等待 |
锁状态 | 无法判断是否已经获取锁 | 可判断是否已经获取到锁 |
锁类型 | 可重入、不可中断、非公平 (只能等待锁释放,不能响应中断) | 可重入、可中断、可公平(两者皆可) (等待锁时可用interrupt来中断等待) |
适用场景 | 简单的线程同步控制。 多线程竞争的概率很高。 | 复杂的线程同步控制(比如:公平锁、读写锁)。 多线程竞争的概率很低。 |
性能 | jdk1.6以前:重量级锁(无法取得锁即挂起,性能差) jdk1.6之后:优化了性能:给它的锁加入了四种状态,无锁状态 -> 偏向锁 -> 轻量级锁 -> 重量级锁,自动进行锁的升级。 | jdk1.6以后: Lock性能略好于synchronized |
synchronized与ReentrantLock
相同点
项 | 说明 |
同步方式 | 都是加锁方式同步 |
是否可重入 | 都是可重入锁 |
是否阻塞 | 都是阻塞式的同步 |
不同点
因为ReentrantLock实现了Lock,所以拥有synchronized与Lock的所有不同点,其他不同点如下:
项 | synchronized | ReentrantLock |
锁条件个数 | 1个 | 可以多个 |
请先
!