• 线程基础知识 03 synchronized锁(对象在内存的布局和加上锁后对象在内存中的变化)


    1 线程不安全演示

    public class ThreadAndLockTest1 {
        private static int a = 0;
        public static void main(String[] args) throws InterruptedException {
            CountDownLatch la = new CountDownLatch(2);
            for (int t = 0;t < 2;t++){
                new Thread(()->{
                    for (int i = 0;i < 100000;i++) {
                        a++;
                    }
                    la.countDown();
                }).start();
            }
            la.await();
            System.out.println(a);
        }
    }

    如果线程安全,那么打印结果应该是200000

    执行结果,发现不是期望的结果,说明线程不安全

    149202

     

    2 锁演示

    上面代码加上锁(synchronized)之后

    public class ThreadAndLockTest1 {
        private static int a = 0;
        public static void main(String[] args) throws InterruptedException {
            CountDownLatch la = new CountDownLatch(2);
            for (int t = 0;t < 2;t++){
                new Thread(()->{
                    synchronized (ThreadAndLockTest1.class){
                        for (int i = 0;i < 100000;i++) {
                            a++;
                        }
                    }
                    la.countDown();
                }).start();
            }
            la.await();
            System.out.println(a);
        }
    }

    执行结果,是期望的结果

    200000

     

    3 对象在内存里面的存储布局(Oracle的虚拟机)

      什么东西可以作为一把锁?在解释这个问题之前,先了解对象是由什么构成的?

     

    3.1 它主要分为三个部分

    对象头:对象头又包括两类:markword,class pointer,

    实例数据:instance data,

    对齐填充:padding

     

     

    3.2 markword

      它的大小是8字节

    1)哈希码、

    2)GC年龄分代、

    3)锁的信息

      锁状态标志

      线程持有的锁、

      偏向线程id

      偏向时间戳

     

    3.3 使用JOL查看对象内存

    https://www.cnblogs.com/jthr/p/15980849.html

     

    4 查看上锁对象在内存中布局

    上面我们知道了对象的组成和怎么去看对象中的布局,现在我们来看下对象在上锁前、上锁中、上锁后的变化

     

    4.1 示例代码

    public class JolTest {
    
    </span><span style="color: #0000ff;">static</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> T{
    }
    
    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) {
        T o </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> T();
        System.</span><span style="color: #0000ff;">out</span><span style="color: #000000;">.println(ClassLayout.parseInstance(o).toPrintable());
        synchronized (o){
            System.</span><span style="color: #0000ff;">out</span><span style="color: #000000;">.println(ClassLayout.parseInstance(o).toPrintable());
        }
        System.</span><span style="color: #0000ff;">out</span><span style="color: #000000;">.println(ClassLayout.parseInstance(o).toPrintable());
    }
    

    }

     

    4.2 执行结果

    发现上锁后对象头中的markword发生的变化,解锁后又恢复了。

    上锁实际上是在对象头上做了个标记

     

      在这里插入图片描述

     001代表无锁

     00代表轻量级锁

      

  • 相关阅读:
    单例类
    日期类2
    日历类
    日期转换类
    抓取网页内容并截图
    关于计时器与多线程
    让页面上图片不变形
    Thread 调用方法的方式
    语音放大缩小
    阻止Enter键回发到服务端Asp.net
  • 原文地址:https://www.cnblogs.com/jthr/p/15980717.html
Copyright © 2020-2023  润新知