什么是自旋锁?它可能引起什么问题?使用方面有哪些主页实现
自旋锁(SpinLock): 当一个线程在获取锁的时候,如果锁已经被其他的线程获取,那么该线程就会进入循环等待的状态,然后在不停的询问是否成功的获取锁的资源,一直到获取锁的才会退出循环。通常在CAS(Compare and swap)算法中会使用到自旋锁。
适应性自旋锁: JDK1.6之后对自旋锁进行了改进,引入了自适应自旋锁,随着程序的运行和性能的监控,JVM会对锁的情况进行预测,从而给出合适的自旋时间和更加智能.
它可能引起什么问题:1、如果某个线程持有锁的时间过长,就会导致其他等待的获取锁的线程进入循环等待,消耗CPU,使用不当会造成CPU的使用率极高;2、非公平的情况下,无法满足等待时间最长的线程优化获取锁,不公平的锁会造成线程饥饿问题
使用自旋锁的注意问题:1、自旋锁使CPU处于忙碌状态,因此临界区的执行的时间应该尽量短。2、在高并发写,竞争激烈的场景下,资源的冲突概率大,一般少使用自旋锁。
什么是乐观锁,什么是悲观锁:
问题:悲观锁会造成什么劣势
1、造成阻塞,唤醒的现象,从而造成性能劣势
2、可能造成永久阻塞,也就是死锁
3、阻塞的优先级越高,持有锁的优先级越低,从而导致优先级反转问题
问题:什么是乐观锁,什么是悲观锁
悲观锁:在对数据或线程发生更改的时候就会将数据进行加锁,这种加锁其他操作无法访问该数据或线程
lock锁和synchronized锁
乐观锁:在对数据或线程发生更改的时候不会对数据进行加锁,其他操作和数据也可以访问此数据或线程
示例:悲观锁:select *** for update
乐观锁:git操作的push操作
将悲观锁转化为乐观锁:添加版本号
乐观锁的元始开销比乐观锁的小
适用场景:
乐观锁:并发写入小,大部分的操作是读操作
悲观锁:并发写入多,(可以避免大量的自旋锁等消耗)
临界区有竞争激烈,临界区代码复杂,临界区有IO操作
独占锁和共享锁有何区别?ReadWriteLock的独占锁,共享锁是什么?ReentrantLock呢?
独占锁:只能一个线程获得锁
共享锁:多个线程同时获得锁
synchronized,reentrantlock是独占锁,readwritelock的写锁是独占锁,读取是共享锁
semaphore(信号量),countdownlatch都是共享锁
reentrantlock,semaphore,countdownlatch,reentrantreadwritelock都使用AQS(AbstractQueued Synchronizer)实现独占锁和共享锁。
java对象在hotSpot VM的布局包括哪几个部分:
HotSpot VM是sun JDK自带的虚拟机,也会死目前世界上使用范围最广的java虚拟机,java对象在HotSpotVM中包含对象头,实例数据和补齐填充三部分。
java对象的对象头包含:Mork Word和class pointer
数组对象的对象头包含:Mork Word和class pointer,还有length。
对象头:
Mark Word 存储对象的hashCode,锁等信息,比如轻量级锁的标定位,偏向锁标记位等等;在32位系统中占用4个字节,在64位系统中占用8个字节。(我们常说的锁,hashCode都存储在MW)
Klass Pointer(Class pointer):用来指向对应的class对象(其对应的元数据对象)的内存储地址;在32位系统中占用4个字节,在64位系统中占用8个字节。(对象的存储地址在KP当中)
length:如果是数据对象,还有一个保存数组的长度单位,在32位系统和64位系统中都只占用4个字节。
实例数据:
实例数据是对象真正存储的有效信息,就是程序中所定义的各种数据类型和和字段的内容,无论是否从父类继承下来,还是在子类定义的都需要记录下来。
补齐填充:
补齐填充并不是必然存在的,也没有特别的含义,它的作用仅仅是用来作为占位符使用,保证对象头的长长度始终是8字节的倍数。
多线程锁有哪些状态,如何标记锁的状态:
锁有四种状态:无锁,偏向锁,轻量级锁,重量级锁
锁的状态是通过对象的监视器在对象头中的字段来表示的,四种锁会随着竞争的情况逐渐升级,而且该过程不可逆的过程,及该过程是不可降级的。
状态切换是根据竞争激烈的程度进行的,在几乎无竞争的条件下会使用偏向锁,在轻度竞争的条件下,会将偏向锁升级为轻量级锁,在重度竞争的情况下,升级为重量级锁。