浅谈synchronized锁原理

简介: 保证线程安全的一个重要手段就是通过加锁的形式实现,今天盘点一下Java中锁的八股文

Java相关文章



线程安全

  1. 当多个线程同时共享,同一个全局变量或者静态变量,做写的操作时,可能会发生数据冲突问题
  2. 为了避免出现线程安全在必要的时候需要牺牲性能使用锁来保证。


Object监视器模型

  1. 锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中。
  2. 等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池中
  3. 类比AQS中的同步队列与条件队列


synchronized锁原理

  1. Java对象存储在堆中,主要分为三部分,对象头、对象实例数据和对齐补充
  2. 每个对象都有一个与之关联的Monitor 对象存在对象头中
  3. 线程拿锁的过程
  1. 将被锁对象中的 _owner设置成A线程
  2. 所有请求锁的线程首先被放在ContentionList这个竞争队列中;
  3. Contention List 中那些有资格成为候选资源的线程被移动到 Entry List 中;
  4. 任意时刻,最多只有一个线程正在竞争锁资源,该线程被成为 OnDeck;
  5. 当前已经获取到所资源的线程被称为 Owner;


synchroized的锁升级过程

  1. 锁级别由低到高分别是
  1. 无锁
  2. 偏向锁
  3. 轻量级锁
  4. 重量级锁
  1. 升级过程
  1. 线程A在进入同步代码块前,先检查MarkWord中的线程ID是否与当前线程ID一致,如果一致(还是线程A获取锁对象),则无需使用CAS来加锁、解锁
  2. 如果不一致,再检查是否为偏向锁,如果不是,则自旋等待锁释放
  3. 如果是,再检查该线程是否存在(偏向锁不会主动释放锁),如果不在,则设置线程ID为线程A的ID,此时依然是偏向锁。
  4. 如果还在,则暂停该线程,同时将锁标志位设置为00即轻量级锁(将MarkWord复制到该线程的栈帧中并将MarkWord设置为栈帧中锁记录)。线程A自旋等待锁释放。
  5. 如果自旋次数到了该线程还没有释放锁,或者该线程还在执行,线程A还在自旋等待,这时又有一个线程B过来竞争这个锁对象,那么这个时候轻量级锁就会膨胀为重量级锁。重量级锁把除了拥有锁的线程都阻塞,防止CPU空转。
  6. 如果该线程释放锁,则会唤醒所有阻塞线程,重新竞争锁
  1. 根据不同情况也会降级


synchronized锁的范围

  1. 锁是加在对象上面的,我们是在对象上加锁
  2. 锁的标记是记录在对象头中、synchronized原理最终是在代码中加入monitorenter和monitorexit这两个字节码指令保证代码的同步,所以锁的是对象


作用范围

锁对象

非静态方法

当前对象 => this

静态方法

Class对象 => SynchronizedSample.class (一切皆对象,这个是类对象)

代码块

指定对象 => 可以Synchronized(this),也可以Synchronized(Class对象)

相关文章
|
3月前
|
存储 Java 程序员
synchronized的原理以及与ReentrantLock的区别
`synchronized`和`ReentrantLock`均为Java线程同步机制,确保共享资源的单一时刻独占访问。`synchronized`关键字直接嵌入JVM,可通过修饰方法或代码块实现对象锁或监视器锁,具备可重入性,依赖Mark Word进行锁状态管理。`ReentrantLock`则需显式调用`lock()`和`unlock()`,提供更灵活控制,如公平锁、尝试锁及条件变量。两者在语法、灵活性和异常处理上有所差异,但均支持可重入性。性能方面,随JDK优化,`synchronized`在某些场景下甚至优于`ReentrantLock`。选择使用哪个取决于具体需求和上下文。
|
1天前
Synchronized锁原理和优化
Synchronize是通过对象头的markwordk来表明监视器的,监视器本质是依赖操作系统的互斥锁实现的。操作系统实现线程切换要从用户态切换为核心态,成本很高,此时这种锁叫重量级锁,在JDK1.6以后引入了偏向锁、轻量级锁、重量级锁 偏向锁:当一段代码没有别的线程访问,此时线程去访问会直接获取偏向锁 轻量级锁:当锁是偏向锁时,有另外一个线程来访问,偏向锁会升级为轻量级锁,这个线程会通过自旋方式不断获取锁,不会阻塞,提高性能 重量级锁:轻量级锁自旋一段时间后线程还没有获取到锁,线程就会进入阻塞状态,该锁会升级为重量级锁,重量级锁时,来竞争锁的所有线程都会阻塞,性能降低 注意,锁只能升
13 5
|
4月前
多线程线程安全问题之synchronized和ReentrantLock在锁的释放上有何不同
多线程线程安全问题之synchronized和ReentrantLock在锁的释放上有何不同
|
Java 编译器
Java多线程(4)---死锁和Synchronized加锁流程
Java多线程(4)---死锁和Synchronized加锁流程
73 0
|
6月前
|
安全 Java
大厂面试题详解:synchronized的偏向锁和自旋锁怎么实现的
字节跳动大厂面试题详解:synchronized的偏向锁和自旋锁怎么实现的
73 0
|
Java 编译器 Linux
【多线程】锁策略、CAS、Synchronized
锁策略, cas 和 synchronized 优化过程
|
6月前
|
存储 安全 Java
Synchronized锁工作原理
Synchronized锁工作原理
|
安全 Java 编译器
CAS 与 synchronized 原理
CAS 与 synchronized 原理
76 0
|
安全 Java
synchronized 锁与 ReentrantLock 锁的区别
synchronized 锁与 ReentrantLock 锁的区别
111 0
|
存储 Java
synchronized锁升级原理
synchronized锁升级原理
263 1
synchronized锁升级原理