synchronized关键字(作用 + 特点 + 锁升级 + 锁优化 + 与 volatile 对比)

简介: 1. synchronized 的作用1)保证原子性2)保证内存可见性3)保证有序性2. synchronized 特点3. 锁升级的过程1)偏向锁2)轻量级锁3)重量级锁4. 锁的优化操作1)锁消除2)锁粗化5. synchronized 使用示例1)修饰普通方法:锁当前实例对象2)修饰静态方法:锁当前类对象3)修饰代码块:指定锁哪个对象6. volatile 的作用1)保证内存可见性2)保证有序性7. synchronized 和 volatile 的区别

1. synchronized 的作用

1)保证原子性

synchronized 会起到互斥效果,某个线程执行到某个对象的 synchronized 中时,其他线程如果也执行到同一个对象 synchronized 就会阻塞等待


进入 synchronized 修饰的代码块,相当于加锁

退出 synchronized 修饰的代码块,相当于解锁

2)保证内存可见性

synchronized 的工作过程:


获取互斥锁

从主存中拷贝变量的最新副本到工作内存

执行代码

将更改后的共享变量的值刷新到主内存中

释放互斥锁

synchronized 在工作的过程中,synchronized 会将自己更改后的变量直接刷新到主存中,所以其他线程可以看到本线程对变量做的操作,保证了内存可见性


3)保证有序性

有序性: 为了提高性能,编译器和处理器会对指令进行重排序,但是不管怎么重排序程序的执行结果不能改变。重排序不会影响单线程代码的执行,但是在多线程中就容易出问题。


被 synchronized 修饰的代码块在多线程之间是串行执行的,当前线程在执行本代码块时,其他线程是不能进入的


2. synchronized 特点

开始是乐观锁,如果频繁遇到锁冲突,就转换为悲观锁

开始时轻量级锁,如果锁被持有的时间较长,就转换成重量级锁

是不公平锁

是可重入锁

不是读写锁


3. 锁升级的过程

JVM 将 synchronized 锁分为 无锁、偏向锁、轻量级锁、重量级锁 状态。根据情况,进行依次升级

50.png


1)偏向锁

第一个尝试加锁的线程,优先进入偏向锁状态


偏向锁不是真正的加锁,是在对象头中做一个标记,记录这个锁属于哪个线程,如果后续没有其他线程来竞争锁,就不用在进行其他加锁操作,避免了加锁解锁的开销


当后续有其他线程来竞争锁,就取消偏向锁状态,进入轻量级锁状态


2)轻量级锁

随着其他线程的竞争,偏向锁状态消除,进入轻量级锁状态,其他竞争该锁的线程就会进入自旋状态,不断地尝试加锁


此处的轻量级锁就是通过 CAS 实现的


3)重量级锁

当锁被同一个线程持有时间过长,其他线程自旋的次数过大时,轻量级锁就会膨胀为重量级锁,其他竞争该锁的线程进入阻塞状态


4. 锁的优化操作

1)锁消除

在一些应用程序中,用到了 synchronized,但其实没有在多线程环境下,不可能存在线程不安全的情况,JVM 就会将这些锁进行清除,消除加锁解锁时的资源开销


2)锁粗化

如果一段连续的操作对同一个对象频繁进行加锁解锁,JVM 就会自动把这个锁粗化,也就是扩大这个锁的加锁范围到一整个操作序列。以此来减少加锁解锁的资源开销


5. synchronized 使用示例

1)修饰普通方法:锁当前实例对象

public synchronized void method() {
    // 锁当前实例对象
}

2)修饰静态方法:锁当前类对象

public static synchronized void method1() {
    // 锁当前类对象
}

3)修饰代码块:指定锁哪个对象

public void method2() {
    // 指定锁哪个对象
    synchronized(this) {
        // 锁当前实例对象
    }
    synchronized(SynchronizedDemo.class) {
        // 锁当前类对象
    }
}

6. volatile 的作用

1)保证内存可见性

volatile 会使虽有对被 volatile 修饰的变量的修改直接吸入主存中,使得一个线程对变量的修改对其他线程可见


2)保证有序性

volatile 使用内存屏障机制来达到禁止指令重排序,以此来保证有序性


内存屏障:


内存屏障就是一类同步屏障指令,是CPU或者编译器在对访问的操作中的一个同步点,只有在此点之前的所有读写操作都执行后才可以执行此点之后的操作。


7. synchronized 和 volatile 的区别

volatile 用来修饰变量,synchronized 用来修饰方法和代码块

volatile 只能可以保证代码修改的可见性,synchronized 可以保证原子性和可见性

volatile 不会造成线程阻塞,synchronized 会造成线程阻塞

volatile 背后没有优化操作,JVM 对 synchronized 有优化操作

volatile 本质是告诉 JVM 当前变量工作内存中的值是不确定的,需要从主存中进行读取,synchronized 则是直接锁定当前变量,使得只有当前线程才能访问,其他线程会被阻塞


目录
相关文章
|
6月前
|
存储 缓存 安全
关于Synchronized锁升级,你该了解这些
关于Synchronized锁升级,你该了解这些
94 3
|
4月前
线程可见性和关键字volatile
线程可见性和关键字volatile
|
6月前
|
安全 Java 编译器
Java多线程基础-6:线程安全问题及解决措施,synchronized关键字与volatile关键字(一)
线程安全问题是多线程编程中最典型的一类问题之一。如果多线程环境下代码运行的结果是符合我们预期的,即该结果正是在单线程环境中应该出现的结果,则说这个程序是线程安全的。 通俗来说,线程不安全指的就是某一代码在多线程环境下执行会出现bug,而在单线程环境下执行就不会。线程安全问题本质上是由于线程之间的调度顺序的不确定性,正是这样的不确定性,给我们的代码带来了很多“变数”。 本文将对Java多线程编程中,线程安全问题展开详细的讲解。
96 0
|
6月前
|
Java 编译器 程序员
synchronized 原理(锁升级、锁消除和锁粗化)
synchronized 原理(锁升级、锁消除和锁粗化)
|
Java
synchronized 关键字对于锁的一些优化
synchronized 关键字对于锁的一些优化
63 0
|
安全 Java 编译器
volatile 与 synchronized 关键字的区别?
volatile 与 synchronized 关键字的区别?
54 0
|
存储 Java
synchronized锁升级原理
synchronized锁升级原理
262 1
synchronized锁升级原理
|
缓存 Java 数据库
synchronized锁升级的过程
之前只是了解过一些悲观锁的底层原理,和他具体是如何锁住线程的一些细节,正好今天休息,结合一些文章和自己的实践操作,整理成了一篇关于synchronized锁升级的过程,希望能对大家有所帮助.
185 0
synchronized锁升级的过程
|
存储 安全 Java
Synchronized与锁升级
Synchronized与锁升级
Synchronized与锁升级
|
安全 Java 对象存储
浅谈synchronized锁原理
保证线程安全的一个重要手段就是通过加锁的形式实现,今天盘点一下Java中锁的八股文
155 0