多线程与高并发
1.请描述synchronized和reentrantlock的底层实现及重入的底层原理 --百度阿狸
实现过程:代码:(锁状态的进入和退出)执行过程中自动升级偏向锁自旋锁重量锁汇编的层级实现的,是更为底层的东西
2.请描述锁的四种状态和升级过程
3.CAS的ABA问题如何解决
4.请谈一下AQS,为什么AQS的底层是CAS+volatile
7.CAS是什么
CAS是compare and swap的缩写,即我们所说的比较交换。cas是一种基于锁的操作,而且是乐观锁。在java中锁分为乐观锁和悲观锁。悲观锁是将资源锁住,等一个之前获得锁的线程释放锁之后,下一个线程才可以访问。而乐观锁采取了一种宽泛的态度,通过某种方式不加锁来处理资源,比如通过给记录加version来获取数据,性能较悲观锁有很大的提高。
8.请描述一下对象的创建过程
9.对象在内存中的内存布局
10.DCL单例为什么要加volatile
11.解释一下锁的四种状态
12.Object o=new Object()在内存中占了多少字节?
Object o = new Object(); System.out.println(ClassLayout.parseInstance(o).toPrintable()); 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 markwork 对象头 8个字节 class pointer 类型指针 4个字节 instance data 实例数据 new对象 没有 0字节 现在总共12字节 不能被8整除,所以后面要加4个 空字节占位,凑够16个 可以被8 整除 result:Object对象创建一共在内存中占了16个字节
13.请描述synchronized和ReentrantLock的异同?
14.聊聊你对as -if -serial 和happens-before语义的理解
15.你了解ThreadLocal吗 你知道ThreadLocal中如何解决内存泄漏问题吗
16.请描述一下锁的分类以及JDK中的应用
17.系统底层如何实现数据一致性
-
1.MESI如果可以解决就用MESI(缓存一致性协议之一EMSI)
-
2.如果不能,就锁总线
5.请谈一下你对volatile的理解
-
保证线程可见性,如果该值a被别的线程改变,会实时读取更新的数据值,每次操作都会读取它最新的值
6.volatile的可见性和禁止指令重排序是如何实现的
MESI cache 一致性协议:
-
多核CPU的情况下有多个一级缓存,如何保证缓存内部数据的一致,不让系统数据混乱。这里就引出了一个一致性的协议MESI。
-
MESI(在汇编层)的主要思想:当CPU写数据时,如果该变量是共享数据,给其他CPU发送信号,使得其他的CPU中的该变量的缓存行无效。 在MESI之前,采用总线锁:即多线程下,当某个线程要访问数据,则需要获取这条数据的锁,这样会影响性能。CPU每次会从内存中读取一个缓存行大小的数据(即64byte),如果该数据大于64byte则需要多个缓存行,此时MESI协议失效,加总线锁。
状态 | 描述 | 监听任务 |
---|---|---|
M 修改 (Modified) | 该Cache line有效,数据被修改了,和内存中的数据不一致,数据只存在于本Cache中。 | 缓存行必须时刻监听所有试图读该缓存行相对就主存的操作,这种操作必须在缓存将该缓存行写回主存并将状态变成S(共享)状态之前被延迟执行。 |
E 独享、互斥 (Exclusive) | 该Cache line有效,数据和内存中的数据一致,数据只存在于本Cache中。 | 缓存行也必须监听其它缓存读主存中该缓存行的操作,一旦有这种操作,该缓存行需要变成S(共享)状态。 |
S 共享 (Shared) | 该Cache line有效,数据和内存中的数据一致,数据存在于很多Cache中。 | 缓存行也必须监听其它缓存使该缓存行无效或者独享该缓存行的请求,并将该缓存行变成无效(Invalid)。 |
I 无效 (Invalid) | 该Cache line无效。 | 无 |
volatile如何解决指令重排序
1: volatile i(源码) 2: ACC_VOLATILE 3: JVM的内存屏障:屏障两边的指令不可以重排,保障它的有序。(JVM层面) 4:hotspot实现
19.系统底层如何保证有序性
-
1.内存屏障 sfence mfence ifence等系统原语
-
2.锁总线
JSR内存屏障
LoadLoad屏障: 对于这样的语句Load1;LoadLoad;Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。 StoreStore屏障: 对于这样的语句Store;StoreStore;Store2.在Store2及后续写入操作执行前,保证Store1的写入操作对其他处理器可见。 LoadStore屏障 对于这样的语句Load1;LoadStore;Store2,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。 StoreLoad屏障 对于这样的语句Store1;StoreLoad;Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。
volatile实现过程:
1.保证线程可见性
2.描述锁的四种状态以及升级过程
无锁:new
偏向锁:大部分时候只是同一个线程运行(锁的状态偏向于这个线程)【无锁】【mark word中保留这条线程的信息】场景:大部分时间同一线程执行
自旋锁:有多个线程同时运行时,撤销偏向锁,升级为自旋锁【CAS】场景:线程锁的时间很短
重量级锁:由于某些线程锁的时间过长,自旋锁就会持续不断的自旋【CAS】,占用了大量cpu,升级为重量级锁,向操作系统申请资源。linux mutex , CPU从3级-0级系统调用,线程挂起,进入等待队列,等待操作系统的调度,然后再映射回用户空间。
线程进入一个队列【阻塞状态】,cpu通知锁释放时,队列里的进程才激活。场景:线程锁的时间较长
并发编程的三大特性
**
原子性** 原子性:即一个或者多个操作作为一个整体,要么全部执行,要么都不执行,并且操作在执行过程中不会被线程调度机制打断;而且这种操作一旦开始,就一直运行到结束,中间不会有任何上下文切换(context switch)。 **可见性** 可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看到修改的值。 **有序性** 有序性:即程序执行的顺序按照代码的先后顺序执行。
22.强软弱虚Java中的引用类型