java--Synchronized

Synchronized能够实现:
原子性,
线程解锁时,必须把共享变量的值刷新到主内存中。
线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时从主内存中获取最新的值。

synchronized支持可重入性,即是一把可重入锁
验证代码如下

//--------------------------Synchronized可重入测试---------------------
    public static class Phone {

        public synchronized void sendEmail(){
            System.out.println(Thread.currentThread().getId()+" 发生邮件");
        }

        public synchronized void sendMsg(){
            System.out.println(Thread.currentThread().getId()+" 发生短信");
            sendEmail();
        }
    }

    @Test
    public void test01(){
        Phone phone=new Phone();
        new Thread(new Runnable() {
            @Override
            public void run() {
                phone.sendMsg();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                phone.sendMsg();
            }
        }).start();

        while (Thread.activeCount()>2){
        }
    }

J a v a 线程是映射到操作系统原生内核线程中的,如果要阻塞和唤醒一条线程, \color{#FF0000}{Java线程是映射到操作系统原生内核线程中的,如果要阻塞和唤醒一条线程,} Java线程是映射到操作系统原生内核线程中的,如果要阻塞和唤醒一条线程,
需要操作系统来帮忙完成,这就不可避免陷入用户态到核心态的转换。进行转换需要耗费很多的时间。 \color{#FF0000}{需要操作系统来帮忙完成,这就不可避免陷入用户态到核心态的转换。进行转换需要耗费很多的时间。} 需要操作系统来帮忙完成,这就不可避免陷入用户态到核心态的转换。进行转换需要耗费很多的时间。
所以说 S y n c h r o n i z a t i o n 是重量级锁 \color{#FF0000}{所以说Synchronization是重量级锁} 所以说Synchronization是重量级锁

如下代码

public class Sequence {

    private static Integer i=0;

    public static int getNext(){
        synchronized (Sequence.class){
            return ++i;
        }
    }
}

通过javap -verbose得字节码

public static int getNext();
    descriptor: ()I
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=0
         0: ldc           #2                  // class test/test202106/Sequence
         2: dup
         3: astore_0
         4: monitorenter
         5: getstatic     #3                  // Field i:Ljava/lang/Integer;
         8: invokevirtual #4                  // Method java/lang/Integer.intValue:()I
        11: iconst_1
        12: iadd
        13: invokestatic  #5                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        16: dup
        17: putstatic     #3                  // Field i:Ljava/lang/Integer;
        20: invokevirtual #4                  // Method java/lang/Integer.intValue:()I
        23: aload_0
        24: monitorexit
        25: ireturn
        26: astore_1
        27: aload_0
        28: monitorexit
        29: aload_1
        30: athrow
      Exception table:
         from    to  target type
             5    25    26   any
            26    29    26   any
      LineNumberTable:
        line 13: 0
        line 14: 5
        line 15: 26
      StackMapTable: number_of_entries = 1
        frame_type = 255 /* full_frame */
          offset_delta = 26
          locals = [ class java/lang/Object ]
          stack = [ class java/lang/Throwable ]

进入synchronized代码块,通过monitorenter指令获取对象锁,存储在对象头中,退出时通过monitorexist指令释放对象锁。

synchronized缺陷
1 试图获取锁不能设置超时时间,一直尝试去获取锁,不成功不罢休。
2 锁的释放情况少。只能代码块执行完或者出现异常才会释放锁。
3 不能中断一个正在执行中的线程。
4 不够灵活,加锁和释放锁的时机单一,每个锁仅有单一的条件,像读写锁就比较灵活。

synchronized注意点
1 锁对象不能为空,因为锁存储到对象中。
2 作用域不宜过大。
3 优先用juc包中的工具,然后才是用Lock、synchronized

头对象
在这里插入图片描述
摘自:https://blog.csdn.net/u014044812/article/details/124302959

锁升级过程
cas mark word为当前线程,另外一个线程在 stop the world后检测锁对应的线程,如果线程还存活,那么修改锁标志位为轻量级锁,然后开始自旋,自旋一定次数后锁升级为重量级锁,然后线程阻塞。

无锁-》偏向锁

    @Test
    public void test0000() throws InterruptedException {
        Object obj = new Object();

        log.info(ClassLayout.parseInstance(obj).toPrintable());

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (obj) {
                    System.out.println(Thread.currentThread().getId());
                    log.info(ClassLayout.parseInstance(obj).toPrintable());
                }
            }
        }, "偏向锁测试线程");
        thread.start();

        thread.join();
        log.info("run over");
    }
     * 无锁-》偏向锁,
     * 需要添加jvm参数:-XX:BiasedLockingStartupDelay=0 取消延迟偏向锁 参考:https://ask.csdn.net/questions/7509970
     * <p>
     * 2023-02-09 17:11:39,336 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
     * OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
     * 0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
     * -- 锁定可偏向、未锁定状态
     * 4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     * 8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     * 12     4        (loss due to the next object alignment)
     * Instance size: 16 bytes
     * Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
     * <p>
     * 2023-02-09 17:11:39,342 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [偏向锁测试线程] - java.lang.Object object internals:
     * OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
     * 0     4        (object header)                           05 48 e8 1e (00000101 01001000 11101000 00011110) (518539269)
     * -- 锁定可偏向、偏向锁状态,线程id
     * 4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     * 8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     * 12     4        (loss due to the next object alignment)
     * Instance size: 16 bytes
     * Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

无锁不偏向-》轻量级锁 执行了hashCode方法

    @Test
    public void test0001() throws InterruptedException {
        Object obj = new Object();

        log.info(ClassLayout.parseInstance(obj).toPrintable());

        log.info("hashCode:{}", obj.hashCode());

        log.info(ClassLayout.parseInstance(obj).toPrintable());

        Thread thread01 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (obj) {
                    log.info(ClassLayout.parseInstance(obj).toPrintable());
                }
            }
        }, "线程1");
        thread01.start();

        thread01.join();
        log.info("run over");
    }
     * 无锁不偏向-》轻量级锁 执行了hashCode方法
     * <p>
     * 执行hashCode后直接进入轻量级锁,需要添加jvm参数:-XX:BiasedLockingStartupDelay=0,关闭偏向锁的延迟触发。 https://blog.csdn.net/u014044812/article/details/124302959
     * <p>
     * 未锁定状态,可偏向,
     * 2023-02-09 17:05:12,549 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
     * OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
     * 0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
     * 4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     * 8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     * 12     4        (loss due to the next object alignment)
     * Instance size: 16 bytes
     * Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
     * <p>
     * 执行了hashCode
     * 2023-02-09 17:05:12,550 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - hashCode:586617651
     * 2023-02-09 17:05:12,551 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
     * OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
     * 0     4        (object header)                           01 33 13 f7 (00000001 00110011 00010011 11110111) (-149736703)
     * -- 变为不偏向
     * 4     4        (object header)                           22 00 00 00 (00100010 00000000 00000000 00000000) (34)
     * 8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     * 12     4        (loss due to the next object alignment)
     * Instance size: 16 bytes
     * Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
     * <p>
     * 2023-02-09 17:05:12,552 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [线程1] - java.lang.Object object internals:
     * OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
     * 0     4        (object header)                           d8 ef 90 1f (11011000 11101111 10010000 00011111) (529592280)
     * -- 状态为轻量级锁
     * 4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     * 8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     * 12     4        (loss due to the next object alignment)
     * Instance size: 16 bytes
     * Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

执行hashcode函数后,会把hashcode值填充到对象mark中,共计8个字节地址

00000001 00110011 00010011 11110111

00100010 00000000 00000000 00000000

变换成可阅读的

00000000 00000000 00000000 00100010 
11110111 00010011 00110011 00000001
没啥用的
00000000 00000000 00000000 0

hashcode,等于打印的586617651
0100010111101110001001100110011 

0
0000
锁标志位位
001

无锁状态-》重量级锁 wait方法

    @Test
    public void test0002() throws InterruptedException {
        Object obj = new Object();

        log.info(ClassLayout.parseInstance(obj).toPrintable());

        Thread thread01 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (obj) {
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                    }
                }
            }
        }, "线程一");
        thread01.start();

        Thread.sleep(100);
        log.info(ClassLayout.parseInstance(obj).toPrintable());

        synchronized (obj) {
            obj.notify();
        }

        thread01.join();
        log.info("run over");
    }
     * 无锁状态-》重量级锁 wait方法
     * 2023-02-10 17:43:24,844 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
     * OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
     * 0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
     * -- 无锁
     * 4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     * 8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     * 12     4        (loss due to the next object alignment)
     * Instance size: 16 bytes
     * Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
     * <p>
     * 2023-02-10 17:43:24,959 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
     * OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
     * 0     4        (object header)                           7a 16 53 1c (01111010 00010110 01010011 00011100) (475207290)
     * -- 重量级锁
     * 4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     * 8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     * 12     4        (loss due to the next object alignment)
     * Instance size: 16 bytes
     * Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

偏向锁-》轻量级锁

    @Test
    public void test0102() throws InterruptedException {
        Object obj = new Object();

        Thread thread01 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (obj) {
                    //进行一些耗时操作
                    String test = "";
                    for (int i = 0; i < 10000; i++) {
                        test += "2";
                    }
                }
            }
        }, "线程1");
        thread01.start();
        //让线程一获取到锁
        Thread.sleep(100);

        //偏向锁
        log.info(ClassLayout.parseInstance(obj).toPrintable());

        synchronized (obj) {
            //轻量级锁,因为锁还被线程1获取,那么就会升级为轻量级锁
            log.info(ClassLayout.parseInstance(obj).toPrintable());
        }

        while (Thread.activeCount() > 2) {
            Thread.sleep(500);
        }
        log.info("run over");
    }
     * 2023-02-10 17:11:02,637 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
     *  OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
     *       0     4        (object header)                           25 d0 7e 1f (00100101 11010000 01111110 00011111) (528404517)
     *                                                                             -- 偏向锁
     *       4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     *       8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     *      12     4        (loss due to the next object alignment)
     * Instance size: 16 bytes
     * Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
     *
     * 2023-02-10 17:11:02,638 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
     *  OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
     *       0     4        (object header)                           50 e3 1f 03 (01010000 11100011 00011111 00000011) (52421456)
     *                                                                             -- 轻量级锁
     *       4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     *       8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     *      12     4        (loss due to the next object alignment)
     * Instance size: 16 bytes
     * Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

偏向锁-》重量级锁

    @Test
    public void test0103() {
        Object obj = new Object();

        //无锁,可偏向
        log.info(ClassLayout.parseInstance(obj).toPrintable());

        synchronized (obj){
            //偏向锁
            log.info(ClassLayout.parseInstance(obj).toPrintable());

            obj.hashCode();

            //重量级锁
            log.info(ClassLayout.parseInstance(obj).toPrintable());
        }

        log.info(ClassLayout.parseInstance(obj).toPrintable());
    }

参考:https://blog.csdn.net/u014044812/article/details/124302959

     *  
     * 偏向锁-》重量级锁 执行了hashCode方法 参考:https://blog.csdn.net/u014044812/article/details/124302959
     * 2023-02-10 16:41:50,465 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
     *  OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
     *       0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
     *                                                                             -- 无锁 可偏向
     *       4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     *       8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     *      12     4        (loss due to the next object alignment)
     * Instance size: 16 bytes
     * Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
     *
     * 2023-02-10 16:41:50,466 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
     *  OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
     *       0     4        (object header)                           05 38 c7 02 (00000101 00111000 11000111 00000010) (46610437)
     *                                                                            -- 偏向锁状态
     *       4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     *       8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     *      12     4        (loss due to the next object alignment)
     * Instance size: 16 bytes
     * Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
     *
     * 2023-02-10 16:41:50,467 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
     *  OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
     *       0     4        (object header)                           8a cf d6 02 (10001010 11001111 11010110 00000010) (47632266)
     *                                                                             -- 重量级锁
     *       4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     *       8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     *      12     4        (loss due to the next object alignment)
     * Instance size: 16 bytes
     * Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
     *
     * 2023-02-10 16:41:50,467 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
     *  OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
     *       0     4        (object header)                           8a cf d6 02 (10001010 11001111 11010110 00000010) (47632266)
     *                                                                             -- 重量级锁
     *       4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     *       8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     *      12     4        (loss due to the next object alignment)
     * Instance size: 16 bytes
     * Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

轻量级锁-》重量级锁

    @Test
    public void test0201() throws InterruptedException {
        Object obj = new Object();
        //无锁状态
        log.info(ClassLayout.parseInstance(obj).toPrintable());

        Thread thread01 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (obj) {
                    //轻量级锁
                    log.info(ClassLayout.parseInstance(obj).toPrintable());
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "线程1");
        thread01.start();

        Thread.sleep(50);

        synchronized (obj) {
            //重量级锁
            log.info(ClassLayout.parseInstance(obj).toPrintable());
        }
        log.info("run over");
    }
     * 轻量级锁-》重量级锁 添加jvm参数:-XX:-UseBiasedLocking 去掉偏向锁过程
     * 2023-02-09 21:00:56,088 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
     * OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
     * 0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
     * 无锁状态
     * 4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     * 8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     * 12     4        (loss due to the next object alignment)
     * Instance size: 16 bytes
     * Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
     * <p>
     * 2023-02-09 21:00:56,093 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [线程1] - java.lang.Object object internals:
     * OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
     * 0     4        (object header)                           00 f5 55 1f (00000000 11110101 01010101 00011111) (525726976)
     * -- 轻量级锁
     * 4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     * 8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     * 12     4        (loss due to the next object alignment)
     * Instance size: 16 bytes
     * Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
     * <p>
     * 2023-02-09 21:00:56,302 INFO [com.txp.owner.basic.record.test202302.TestMain20230209] [main] - java.lang.Object object internals:
     * OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
     * 0     4        (object header)                           9a 83 ce 02 (10011010 10000011 11001110 00000010) (47088538)
     * -- 重量级锁
     * 4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     * 8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     * 12     4        (loss due to the next object alignment)
     * Instance size: 16 bytes
     * Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

摘自网上
请添加图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值