juc-4-synchronized原理
创始人
2024-05-01 00:33:44
0

目录

1、synchronized 作用于静态方法

 总结

​编辑

  案例 静态成员变量 (synchronized锁非静态方法)

  案例 静态成员变量 (synchronized锁静态方法 或 直接锁类)

2、监视器锁(monitor)

2.1 synchronized怎么实现的线程安全呢?

3、JDK6 synchronized 的优化

   3.1 CAS讲解

3.2 synchronized

3.2.1 java对象的布局

 3.2.2 偏向锁

 3.2.3 偏向锁的撤销 

3.2.4轻量级锁(自旋锁/自适应自旋锁)


1、synchronized 作用于静态方法

 总结

  1.  当synchronized作用于静态方法时,其锁就是当前类的class对象锁。由于静态成员不专属于任何一个实例对象,是类成员,因此通过class对象锁可以控制静态 成员的并发操作。
  2.  synchronized作用于非静态方法时,也可以直接锁类。也可以控制静态 成员的并发操作。
  3.  synchronized作用于非静态方法时,必须是同一个对象才能控制静态 成员的并发操作。

需要注意的是如果一个线程A调用一个实例对象的非static synchronized方法,而线程B需要调用这个实例对象所属类的静态 synchronized方法,是允许的,不会发生互斥现象,因为访问静态 synchronized 方法占用的锁是当前类的class对象,而访问非静态 synchronized 方法占用的锁是当前实例对象锁

  案例 静态成员变量 (synchronized锁非静态方法)

   synchronized修饰非静态方法时,锁的是当前实例,不同实例就不是同一把锁了,就不是线程安全 

public class ThreadRunnable5 implements Runnable {private static int a = 100;@SneakyThrows @Overridepublic void run() {while (true) {if (a > 1) {increase4Obj();Thread.sleep(100);}}}public synchronized   void increase4Obj(){System.out.println(Thread.currentThread().getName() + "==" + a);a--;}public static void main(String[] args) {ThreadRunnable5 thread = new ThreadRunnable5();new Thread(thread).start();new Thread(thread).start();}
}

 

  普通方法锁的就是 对象的实例,不同的实例对象时,就是两个锁。无法保证线程安全

  案例 静态成员变量 (synchronized锁静态方法 或 直接锁类)

2、监视器锁(monitor)

一篇就够,synchronized原理详解_小派师兄的博客-CSDN博客_synchronized原理

2.1 synchronized怎么实现的线程安全呢?

2.1 我们反编译下面的代码,看看jvm底层是如何帮助我们实现的线程安全的。

代码

public class ThreadRunnable6  {private static Object obj=new Object();public synchronized void test(){System.out.println("test打印");}public static void main(String[] args) {synchronized (obj){System.out.println("同步代码块");}}
}

执行反编译命令

到目标类的文件夹下
cd target/classes/com/example/juc/create/
对目标类执行命令
javap -p -v -c ThreadRunnable6.class

 找到main方法那段就行

jvm虚拟机规范文档找到指令作用

Chapter 6. The Java Virtual Machine Instruction Set

monitorenter内部结构

可以参考这个博客的一些理解,画的很容易理解,但是也不是很全面

Java并发编程之Monitor工作原理(有图解)_Juice正在路上..的博客-CSDN博客_java monitor原理

java对象头的总体结构,MarkWord的结构、MarkWord和锁的关系_时间都用来泡馍了的博客-CSDN博客_java对象头结构

获取锁资源的流程:

monitor是重量级锁

jvm底层调用会用到内核函数。需要我们由用户态切换到内核态。

那什么是内核态呢?为什么不能直接使用呢?

 我们的应用程序在内存运行的空间叫 用户空间(用户态)。

 它不能直接调用系统的硬件资源,会去损坏我们的硬件(随意删除内存数据,造成死机等)。为了安全,

只有内核能够调用硬件,应用程序靠系统调用,cpu由用户态转为内核态,调用完成后,操作系统会重置cpu为用户态并返回系统调用的结果。  

用户态与内核态来回切换会有大量的系统资源消耗,所以jdk1.6优化了synchronize 。

例如:IO操作,就需要内核态

3、JDK6 synchronized 的优化

   3.1 CAS讲解

跟乐观锁类似,本地内存和主存比较一样即可修改,内存地址和旧的预期值一样 就可以更改 成员变量 。do while用的很好

   

3.2 synchronized

jdk1.6做的优化,无锁---偏向锁---轻量级锁----重量级锁

3.2.1 java对象的布局

对象头:hash码,锁信息(判断是哪种锁状态,重量级锁的指针 moniter位置),gc标志

实例数据:类中属性数据信息,包括父类的属性信息;

对齐数据:jvm分64位和32位, 64位就是8字节,一个对象要被8整除。不够的补齐。

 3.2.2 偏向锁

总结:锁对象结构,一个线程使用的时候,就会是偏向锁,但是有四秒延时,四秒前打印不是偏向锁,四秒后就是偏向锁。

有偏向锁的原因:经过HotSpot作者发现,大多数情况下,锁不仅不存在多线程竞争,而且总是由一个线程多次获取,为了让线程获取锁的代价更低,引入了偏向锁。

偏向锁:会偏向于第一个获取锁的线程,会在对象头存储偏向的线程id。以后该线程进入和退出同步快时只需要检查是否为偏向锁,锁标志位以及ThreadID即可。

偏向锁的基本流程图

步骤二是用CAS保证记录线程id的正确性。

 验证打印对象头信息

        org.openjdk.joljol-core0.9
    private static Object obj=new Object();public static void main(String[] args) {synchronized (obj){System.out.println(ClassLayout.parseInstance(obj).toPrintable());}}

 为什么打印的不是101(偏向锁)?

偏向锁在java1.6是默认启动的,但是要在程序启动后4秒才能激活。可以使用参数关闭延时。如果程序所有锁基本都要处于竞争状态也可以关闭偏向锁。

//关闭延迟开启偏向锁
-XX:BiasedLockingStartupDelay=0
//禁止偏向锁
-XX:-UseBiasedLocking

 3.2.3 偏向锁的撤销 

场景:两个线程竞争的时候就会去撤销偏向锁。

1偏向锁的撤销动作必须等待全局安全点(所有的线程都停下来了)

2暂停拥有偏向锁的线程,判断锁对象是否处于被锁定的状态。

3撤销偏向锁,恢复到无锁(标志位为01)或轻量级锁(标志位为00)的状态

3.2.4轻量级锁(自旋锁/自适应自旋锁)

场景:适用于多个线程交替去获取锁,而不是大量并发去获取锁。

jdk1.4引入自旋锁,1.6引入自适应自旋锁。 如果线程过多很多线程空耗cpu资源。升级为重量级锁(monitor

还有很多细节,实在学的难受,暂时放放。

偏向锁、轻量级锁、自旋锁、重量级锁,看这一篇就够了!_51CTO博客_自旋锁和互斥锁

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...