juc-4-synchronized原理

目录

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 @Override
    public 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的正确性。

 验证打印对象头信息

        <!--查看对象内存布局-->
        <dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.9</version>
        </dependency>
    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博客_自旋锁和互斥锁

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值