一、Synchronized的原理是什么?
1、Synchronized是JVM虚拟机实现的一种互斥同步的方式,被Synchronized修饰的程序块在编译后,生成了monitorenter和monitorexit指令;
当虚拟机执行到monitorenter指令的时候, 首先要尝试获取对象的锁。如果这个对象没有锁定,或者当前线程已经获取了这个对象的锁,把锁的计数器+1;当执行monitorexit指令时候会将锁计数器-1,当计数器为0时,锁就被释放了。
2、如果锁对象获取失败,那么获取锁的线程就会阻塞等待,直到另一个线程释放锁对象为止。
3、JAVA中Synchronized关键字是通过在锁对象头中设置标识,来实现获取锁和释放锁的目的
二、 Synchronized锁有哪几类?
1、明确的锁对象
Synchronized可以明确指定锁对象,比如Synchrnozed(this)或者Synchronized(变量),那么 被Synchrozied指定的变量就是锁对象
2、不明确的锁对象
Synchronized修饰非静态方法时候,那么这个方法对应的对象就是锁对象
Synchronized修饰静态方法的时候,那么这个静态方法对象的类就是锁对象
PS.当一个对象被锁住的时候,这个锁对象内部所有的被Synchronized修改方法都会产生阻塞,没有被Synchronized修饰的方法可以正常被调用,不会产生阻塞
三、什么是可重入锁?Synchronized是可重入锁吗?是怎么实现的?
可重入锁是指当一个线程已经获取某对象锁,当这个线程再次获取该锁对象时候可以获取,不会产生阻塞。
Synchrnozied是可重入锁。Synchronized的锁对象头有一个标识,当线程加锁时,会首先判断该对象时候已经上锁,如果没有上锁或者获取锁的是该线程时,锁计数器+1,从而实现的锁的可重入刑。
四、逃逸分析
逃逸是指在方法内部创建对象,除了在方法体内部引用之外,在方法体外还被其他变量引用到;这样的后果就是 在该方法执行完之后,由于其被其他变量引用。在该方法中创建的对象无法被GC回收,
五、为什么说Synchronized是非公平锁
公平锁和公平锁主要是表现在获取锁的行为上。
公平锁是按照申请获取锁的顺序来给线程分配锁对象的
非公平锁并不是按照申请锁的顺序来给线程分配锁,每当锁释放时,任何一个线程都有机会竞争获取锁,这样做的目的是可以提高执行性能,缺点是可能会产生线程饥饿
六、 什么是锁粗化和锁消除
锁消除:在虚拟机即时编译器运行时,对于一些代码要求同步,但是检测到没有共享变量竞争,那么就可以对这些锁进行消除。也就是进行了锁消除。
锁粗化:原则上,同步代码块的作用范围约小越好,但是如果一个同步代码获取锁释放锁后,这个同步代码块后面又有获取锁,释放锁等操作,
也就是说有一些列的操作都对同一个锁对象反复进行加锁和释放锁,频繁的加锁和释放锁这样的互斥同步操作也会导致不必要的性能损耗,所有可以考虑进行锁粗化,扩大锁作用的范围。
七、 为什么说Synchronized是悲观锁?
Synchronized的并发策略是悲观的,也就是说Synchronzied是一个悲观锁。
主要是Synchronized修饰的方法或者代码块,不管有没有共享变量或者说根本就不会产生共享变量的竞争,都是会对操作加锁的。这一点来说,Synchronized是一个悲观锁。即时没有共享变量,Synchronized也要考虑维护锁计数器以及考虑线程释放锁之后需要对那些线程进行唤醒等操作。
八、乐观锁的实现原理是什么?乐观锁就一定是好的吗?有什么缺点?
乐观锁实现的原理
1、乐观锁的核心算法是CAS,CAS涉及到三个值:内存值、预期值、新值。当内存值和预期值相等的时候,执行操作,把内存值设置为新值
2、CAS处理的逻辑:先检查内存中的值和之前读取到内存的值是否一致,如果一致,说明期间没有其他线程对内存值进行操作过,可以将内存值设置为新值;如果不一致,说明期间有其他线程对内存中的值进行了操作,则舍弃这次操作
3、CAS的原子性是CPU硬件指令实现保证的,JDK提供了Unsafe类可以对内存直接进行操作
乐观锁的缺点:
1、当存在共享变量的竞争时,乐观锁不会让别的线程阻塞;但是别的线程会自旋等待,也就是不停地循环等待。长时间的自旋导致的开销比较。加入CAS长时间不成功而一直自旋等待,会给CPU带来跟大的开销。
2、ABA问题。乐观锁的核心是基于CAS,比较内存值和预期值是否相等,如果相同则可以进行操作,不相同则舍弃操作。这种逻辑判断其实是不严谨的。比如 内存中的变量A,一个线程把它变为B之后,再设置为A,那么别的线程也会认为内存值和预期值是一样的,会进行操作。其实 别的线程读取到的A值是另外一个线程经过修改之后得到的,这是有问题的。这对于依赖过程值的运算影响是巨大的。解决的思路就是引入版本号,每次变量更新都把版本+1
九、ReentrantLock和Synchronized的实现原理有什么区别?
Synchronized
Synchronized是通过在锁对象的对象头中设置标识来实现获取锁和释放锁的,Synchronized是JVM一种原生的锁实现方式。
ReentrantLock
ReentrantLock以及相关的Lock锁是基于AQS(抽象队列同步器)来实现,AQS内部有一个volatile修饰的init类型的变量state,每个线程对该变量都有可见性,以及每个线程都可以通过CAS操作来原子修改stste的值,从而来控制锁的获取和释放。
十、AQS框架是怎么样的?
AQS的核心思想
1、线程请求的共享资源是空闲的,那么将请求资源的线程设置为有效的工作线程,并且将共享资源的状态设置为锁定状态。释放锁时,将有效的工作线程设置为null,修改共享资源的状态为未锁定状态,并唤醒队列中的其他线程。
2、线程请求的共享资源是被占用的,那么请求资源的线程将会被封装为Node节点放入到CLH队列中,等到锁释放被唤醒
AQS中有一个被volatile修饰的int 变量 state,这个变量就是共享资源,如果线程获取资源成功,通过CAS操作将state的值设置为1,也就是锁定状态,如果获取资源失败,线程封装为Node节点放到队列里面
AQS中还有一个表示占用共享资源的线程,如果没有线程占用共享资源,那么有效的工作线程为null,如果某一个线程获取资源成功,那么占用资源的线程就为该线程,锁释放时,会将占用资源的线程设置为null
AQS中还有一个CLH虚拟的双向队列,里面存储了请求资源获取不到资源的线程节点,其中线程节点是包装的Node节点,里面包含了 等待线程的信息,等待的状态、链表的上一个节点、链表的下一个节点。
大白话就是:AQS是基于CLH队列,用volatile修饰的变量state,线程通过CAS修改state的值,修改成获取锁成功,执行逻辑,修改state失败,获取锁失败,放入CLH队列,等待被唤醒
十一、ReentrantLock是怎么实现可重入性的?
首先ReentrantLock也是基于AQS的,AQS维护了一个volatile变量state,当前有效的工作线程和双向队列。
当线程首次获取锁成功后,会CAS操作将state的设置为1,并将当前有效的工作线程这设置为这个线程
当该线程再次请求获取锁是,会判断当前的有效的额工作线程是不是该线程,如果是该线程,获取锁成功,cas操作state的值+1,
如果不是当前线程,把该线程封装为Node节点放入到CLH队列的队尾。
从而实现了lock的可重入性
十二、 JUI有哪些并发工具?都有那些同步器?
十三、volatile能够保证线程之间的可见性,能确定保证变量运算是并发安全的吗?