JUC面试
# JUC面试
# 一、Volatile和Synchronized有什么区别?Volatile能不能保证线程安全?DCL单例为什么要加Volatile?什么是指令重排?
1.Synchronized是关键字,用于加锁。而Volatile是用来保证变量的线程可见性(每次线程访问该变量得到的都是最新的值),但是不具有原子性,因此并不能保证线程安全,一般用于一个线程写,多个线程读的场景。
2.DCL单例加入Volataile目的是防止指令重排,造成高并发场景下的线程安全问题 。
3.指令重排是指JVM为了调高性能,在不影响结果的条件下,不按照编码的顺序执行语句。
# 二、JAVA锁机制是怎样的?偏向锁、轻量级锁、重量级锁有什么区别,如何升级?什么是CAS?
1.JAVA的锁就是在对象Markword中记录的一个锁状态,并根据资源竞争激烈程度,不断升级锁,分为无锁,偏向锁,轻量级锁,重量级锁。
2.偏向锁可以理解为锁偏向于第一个获取它的线程,创建的第一个线程则上偏向锁,当该进程下次再想获得锁时,不需要再获得锁;若存在竞争则升级为轻量级锁,通过CAS 避免了使用互斥量的开销,其他的进程不断自旋等待更新;当有非常多自旋的进程时(存在线程之间的同时竞争,CAS失败),JVM上报操作系统升级为重量级锁,每一步都让操作系统来管理,效率比较低。

可以理解为偏向锁相当于只有一个线程在临界区;轻量级锁相当于有多个线程交替访问临界区,你用完给我,我用完给你;而重量级锁相当于是同时有多个线程想要进入临界区。
3.锁又可以分为悲观锁(synchronized)和乐观锁(CAS),前者性能比较差。CAS就是通过比较和交换,有三个操作数V,A和B,要进行修改操作时,先把要写入内存地址V的值取出来赋给A(旧预期值),然后把修改后结果赋给B,当要把B写入V时,要检查A和当前V地址的值是否相同,若相同则写入B,否则重复以上操作更新A,B重新写入。
# 三、谈谈对AQS的理解。AQS如何实现可重入锁?
1.AQS是一个JDK提供的显示锁的框架,Lock类操作通过内部类Sync类来实现,而Sync类又继承了AQS类;在AQS类当中,有一个双向线程队列,还有一个state信号量,通过该信号量来控制线程排队放行的。不同场景下有不同意义。
2.可重入锁是指对同一个线程而言,该线程可以lock()多次获得多个锁,一般适用于线程需要多次进入临界区的场景。在可重入锁场景下,state用来记录锁的计数值,每lock()一次就加1,release()则减一,直到减为0其他线程才能进入临界区。
# 四、有A,B,C三个线程,如何保证三个线程同时执行?如何在并发情况下保证三个线程依次执行?如何保证三个线程有序交错进行?
1.线程同时执行(或者一个线程等多个线程)使用CountDownLatch,初始时先设定一个计数器,每当一个任务执行完则CountDownLatch.countDown()使计数器减一,当计数器减为0时,被CountDownLatch.await()阻塞的线程唤醒,执行await()往下的代码。
2.依次执行可以使用volataile变量来控制;有序交错执行都可以使用Semaphore信号量,B要在A执行完后才执行,则A执行完后需要release()释放B的信号量,B中acquire()获得信号量后才能执行往下的代码。
# 五、为什么wait,notify方法不定义在thread中?
因为java的锁是对象级的,对象通过线程获得锁,锁是属于对象的。如果定义在thread中,那么线程等待的是哪的锁就不是很明确。