并发编程面试必知必会

310 阅读5分钟

synchronized 在静态方法和普通方法的区别?

  • synchronized在静态方法上,锁住的是类对象

  • synchronized在普通方法上,锁住的是实例对象

synchronized 的实现原理以及锁优化?

实现原理

同步代码块的synchronized 是使用monitorentermonitorexit 指令来实现的,同步方法需要JVM底层实现,依靠的是方法修饰符 上的ACC_SYNCHRONIZED实现。

锁优化过程
无锁

不锁住资源,多个线程中只有一个能修改资源成功,其它线程会重试。

偏向锁

定义:同一个线程执行同步资源时自动获取资源

获取和撤销过程:

获取:线程1访问代码块,检查对象头中是否存储线程1的线程ID,若没有则采用CAS替换对象头的线程ID,若替换成功表明没有其他线程在执行操作,即可执行同步块。

撤销:线程2访问代码块,检查对象头是否存储线程2的线程ID,若没有则采用CAS算法替换,**这时对象头里面已经存储了线程1的线程ID,**因此CAS操作不成功,因此要撤销偏向锁。

应用场景:只有一个线程进入临界区

轻量级锁

定义:多个线程竞争同步资源时,没有获取资源的线程自旋等待释放锁。

应用场景:多个线程交替进入临界区

重量级锁

定义:多个线程竞争同步资源时,没有获取资源的线程阻塞等待唤醒。

应用场景:多个线程同时进入临界区

volatile 的实现原理?

为了提高处理速度,系统先将内存的数据缓存,处理器和缓存数据进行传输。

  • 在生成汇编代码的时候,会出现LOCK前缀指令
  • LOCK前缀指令会引起处理器的缓存写会内存,一个处理器缓存到内存会导致其他处理器的缓存失效
  • 每个处理器为了实现数据缓存一致性,会通过嗅探机制来检查自己缓存的数据是否过期,如果过期则会从内存中获取最新值。

怎么实现所有线程在等待某个事件的发生才会去执行?

CountDownLatch

通过构造方法设置线程的个数,每个线程执行完操作调用countDown(),调用await()方法,当count为0 时,才会执行下面的事件。

CyclicBarrier

CyclicBarrier用于多个线程间的相互等待,等全部完成再继续执行下面的事情。可以类比10个人开会,只有等到10个人才能开始下面的流程。

什么是Semaphore?

semaphore可以理解为信号量,用于控制资源并发访问的数量。线程通过acquire()获取许可证后,该线程才能继续往下进行,当业务功能执行完毕后,通过release()释放许可证,让其它线程获取。

什么是CAS?CAS 有什么缺陷,如何解决?

  • CAS是一种乐观锁策略,通过比较交换来鉴别线程是否出现冲突,如果冲突就重试当前操作指导没有冲突为止。通俗的讲,如果预估的值内存地址存放的实际值相等,则做更新操作
ABA问题

描述:比如一个旧值A变成了B,然后又变成了A,此时在做CAS时发现旧值并没有变化依然为A,但是实际上的确发生变化。

解决方案:加版本号时间戳

自旋时间过长

描述: 使用CAS是非堵塞同步,会不停的自旋,会对性能造成损耗。

synchronized 和 lock 有什么区别?

  • Lock是一个接口,而synchronized是一个JAVA关键字。
  • Synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生。而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则可能会造成死锁现象,因此在使用Lock的时候,需要在finally块中释放锁。

Hashtable 是怎么加锁的 ?

Hashtable大多数方法都是在方法体上使用synchronized关键字进行修饰的,比如get()put()remove()等,保证了安全性,但是却大大降低了执行效率。

ConcurrenHashMap 介绍?

1.6版本:采用分段锁,每一个节点都是一把锁

1.8版本:采用CAS+synchronized

线程池的种类,区别和使用场景?

newCachedThreadPool
  • 定义:当有新任务到来,首先会在线程池里面寻找线程来执行,若有则执行,若没有则创建一个线程来执行该任务。
  • 使用场景:执行短期异步的小程序或者负载较轻的服务器。
newFixedThreadPool
  • 定义:创建可容纳固定数量的线程池。
  • 使用场景:执行长期的任务。
newSingleThreadExecutor
  • 定义:只创建一个线程的线程池。
  • 使用场景:一个任务一个任务的执行场景。
newScheduleThreadPool
  • 定义:创建一个固定大小的线程池,线程池被线程存活时间无限制,线程池可以支持定时及周期性任务执行。
  • 使用场景:周期性执行任务场景。

ThreadLocal原理,用的时候需要注意什么?

原理
  • 每个线程都维护一个ThreadLocalMap的引用
  • 调用ThreadLocal的set()方法时,实际上就是往ThreadLocalMap设置值。
内存泄露

由于ThreadLocalMap的生命周期跟Thread一样长,如果没有手动删除对应的key就会导致内存泄露,可以手动remove。