java多线程进阶

理解synchronized的实现

想理解这个东西,我们要做一些知识预备,先明确下面这些问题

CAS问题

全称compare and swap
解决的问题:在无锁的状态下,保证线程一致性(线程安全)的去改共享数据。
1、获取当前共享数据的值,放到E
2、对共享数据进行计算结果,放到V
3、重新获取当前共享数据的值N,与刚才的E比较;相等则将共享数据更新为V,否则继续步骤1
java多线程进阶_第1张图片
ABA问题:过程中存在ABA问题,什么是ABA问题呢?就是其他线程修改数次最后值和原值E相同,也就是原来是A,中间被别人修改了数次,可能是B,但是当你重新读取当前最新值N的时候,发现N=A,没变,这就是ABA问题。
如何解决ABA问题?加版本号,或者加布尔值解决。

cas在java最底层、最终的实现:

lock cmpxchg 指令

对象在内存中的存储布局

要想更直观的了解对象在内存中的存储布局,我们引入一个工具类,我们可以利用这个工具,验证我们对象在内存中存储布局的结论。

        <dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.9</version>
        </dependency>

我们要看下new Object()对象在内存中的存储布局

        Object o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());

运行结果:
java多线程进阶_第2张图片
java多线程进阶_第3张图片
markword:8字节。关于锁定信息记录在markword里面
classpointer:开启压缩的情况下是4个字节;不开启压缩8个字节。java默认压缩
padding(对齐):当整体的字节数不能被8整除的话,要凑够被8整除的数,提高总线读取速度。

我们在命令行敲这个命令,结果如图
java多线程进阶_第4张图片我们可以看到ClassPinter使用压缩,就是4个字节;oops即普通对象指针,也是使用压缩,就是4个字节。

我们回过头来看刚开始的object对象
java多线程进阶_第5张图片
面试题: Object o = new Object()在内存中占了多少个字节?(顺丰)
答:16个字节。

我们再来分析一下下面这个User user = new User();User对象的内存布局:

class User{
    private int id;
    private String name;
}

分析:
markword:8字节
classpointer:默认开启压缩的情况下4字节
int:4字节
string:默认开启普通对象指针压缩的情况下4字节
对齐:4字节
一共24字节

我们借用工具看一下这个对象的内存存储布局:

public class T01 {
    public static void main(String[] args) {
//        Object o = new Object();
//        System.out.println(ClassLayout.parseInstance(o).toPrintable());
        User user = new User();
        System.out.println(ClassLayout.parseInstance(user).toPrintable());
    }
}
class User{
    private int id;
    private String name;
}

运行结果:与我们的分析一致
java多线程进阶_第6张图片
下面聊一聊markword:markword的64位详细记录了锁的信息,

锁升级过程

new —> 偏向锁 —> 轻量级锁(无锁、自旋锁、自适应锁)—> 重量级锁
java多线程进阶_第7张图片

你可能感兴趣的:(后端开发,多线程)