面9-多线程(题)

1、描述synchronized和reentrantlock的底层实现及重入的底层原理

1.1 CAS

1、compare and swap:比较并且交换
没有锁的状态下,保证多个线程对一个锁的更新

public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

2、图解原理:
在这里插入图片描述
3、ABA问题:使用A时,其他线程中间改回B但在实际操作的时候又改回了A(可以加版本号,进行对比值和版本号)
4、汇编指令:lock cmpxchg

1.2 synchronized

1、锁有一个升级过程:
在这里插入图片描述
无锁 --(1)–> 偏向锁 --(2)–> 轻量级锁(自旋锁、自适应自旋) --(3)–> 重量级锁
(1)上厕所,门口贴标签(第一次加锁)
对象头上的某两位,指定锁的什么类型的锁,偏向锁记录这个线程的id值,我们就认为这个锁为这个线程独有,竞争,发生锁升级
(2)只要发生竞争(LR),就升级为轻量级锁(CAS自旋锁)
(3)竞争比较激烈时,向操作系统申请一把大锁,进程在等待队列中等待
2、锁降级
发生在GC状态,
3、锁消除:lock eliminate

void add() {
        StringBuffer sb = new StringBuffer();
        sb.append("li-").append("si");
        System.out.println(sb.toString());
    }

StringBuffer是线程安全的,因为他的方法被synchronized修饰,但上述例子中,sb这个引用只会在add方法中使用,不可能被其他线程引用,(因为是局部变量,栈私有)因此sb是不可能共享的资源,jvm会自动消除StringBuffer对象内部的锁

4、锁粗化:lock coarsening

String addStr() {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 100; i++) {
            sb.append(i);
        }
        return sb.toString();
    }

jvm会监测到这样一连串的操作都会对同一个对象加锁,此时jvm就会将加锁范围粗化到这一连串操作的外部,使得这一连串的操作只需要加一次锁即可

5、JIT:just in time compiler----> 热点代码直接编译成机器语言
6、实现过程:
(1)Java代码:synchronized
(2)字节码指令:MONITORENTER MONITOREXIT
(3)执行过程中自动升级
(4)更底层实现:lock cmpxchg

2、Object o = new Object();在内存中占有的字节数

JOL = java object layout

2.1 对象在内存中的分布:

在这里插入图片描述

2.2 markword+类型指针 -> 对象头

在这里插入图片描述
markword -> 锁的信息 (8字节)
class pointer -> 属于哪个class (4字节)
padding:当对象整体的字节数不可以被8整除的时候,使用padding补齐 -> 提高效率

2.3 结果:

new object 16字节(补齐 压缩之后的 8+4)不压缩的话就是8+8
Object o 引用 4个字节

3、volatile

3.1 基本概念

1、保证线程可见性

public class VolatileCreate {
    volatile boolean flag = true; //  begin -- 
 //end -- 
//    boolean flag = true; // begin -- 
    void run() {
        System.out.println(" begin -- ");
        while (flag){
        }
        System.out.println(" end -- ");
    }
    public static void main(String[] args) {
        VolatileCreate vc = new VolatileCreate();
        new Thread(()->{
            vc.run();
        }).start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        vc.flag = false;
    }
}

2、阻止指令重排序:
(1)乱序执行:读指令的同时可以同时执行不影响的其他指令
写的同时可以进行合并写
这样CPU执行就是乱序的
(2)volatile如何解决指令重排序
volatile
ACC_VOLATILE – 字节码层级
JVM内存屏障
hotspot实现

3.2 缓存行概念:

1、cache line的概念,缓存行对齐 伪共享 - - - - - > 缓存行一致性协议
在这里插入图片描述
2、读数据 按块来读(8字节)
单独占一个缓存行,就不需要重复读取数据,提升性能

3.3 系统底层如何实现数据一致性

1、MESI如果能解决,就使用MESI
2、锁总线

3.4 系统底层如何保证有序性

1、sfence mfence ifence等系统原语
2、锁总线

3.5 内存屏障

屏障两边的指令不可以重排,保证有序
1、JSR内存屏障:
在这里插入图片描述

3.6 volatile的实现细节

1、编译器层面
加了一个volatile关键字
2、JVM层面
在这里插入图片描述

4、ThreadLocal(线程本地变量)

4.1 定义:

是一个线程内部的存储类,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据(只有本线程可以读到,其他线程读不到)
想象成容器,里面可以装对象

4.2 代码理解
public class ThreadLocalTest {
    static ThreadLocal<Person> tl =  new ThreadLocal<Person>();
    public static void main(String[] args) {
        new Thread(()->{
            tl.set(new Person());
        }).start();

        new Thread(()->{
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(tl.get()); // 取不到
        }).start();
    }
}
class Person{
    String name = "lisi";
    public Person() {
        System.out.println(name);
    }
}
4.2 @Trasactional (事务)

本质上是ThreadLocal实现的,从ThreadLocal中取conn,一定是同一个,与线程绑定

5、强软弱虚—Java中的引用类型

5.1 虚引用

get不到
管理堆外内存(操作系统内存)
当对象被回收时,通过Queue可以检测到,然后清理堆外内存
gc、队列

5.2 弱引用

未回收时get到
经过垃圾回收,弱引用指向的对象直接被回收了
NIO依据次实现

5.3 强引用

正常的引用,没有引用的话就被垃圾回收器回收

5.4 软引用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值