面试问答总结之并发编程

文章目录

  • 个人主页:信计2102罗铠威
  • JavaEE系列专栏
    • 前言:
    • 多线程的优点、缺点
    • 并发编程的核心问题 :不可见性、乱序性、非原子性
      • 不可见性
      • 乱序性
      • 非原子性
      • JMM(java内存模型)
      • volatile关键字:保证可见性、禁止指令重排序
      • CAS机制 (Conpare And Swap 比较并交换)
      • CAS会产生ABA问题
    • java中锁的分类
      • 乐观锁、悲观锁
      • 可重入锁
      • 读写锁 ReentrantReadwriteLock
      • 分段锁
      • 自旋锁
      • 共享锁、独占锁
      • 公平锁、非公平锁
        • 针对synchronized锁的状态(底层monitorenter加锁、moniterexit释放锁)
        • ReentrantLock实现
        • AQS (AbstractQueuedSynchronizer,抽象同步队列 在JUC并发包下)
        • 集合可以引申过来:ConcurrentHashMap
        • 集合可以引申过来:CopyOnWriteArrayList
      • 辅助类CountDownLatch
    • 线程池
      • 为什么要使用线程池?
      • 你通常是怎么创建线程池的?为啥不使用其他的类Executors?
      • TreadPoolExecutor构造方法的七个参数
      • 线程池拒绝策略handler
      • execute()与submit()的区别
      • 关闭线程池shutdown、shutdownNow
    • ThreadLocal 本地线程变量
      • 什么原因造成ThreadLocal内存泄漏问题?如何解决?

个人主页:信计2102罗铠威

JavaEE系列专栏

前言:

本篇博客主要总结面试中对线程知识的考察点

多线程的优点、缺点

提高了程序的响应速度,可以多个线程各自完成自己的工作,以提高硬件设备的利用率。
缺点:可能会出现多个线程资源争夺问题,引发死锁。

并发编程的核心问题 :不可见性、乱序性、非原子性

不可见性

一个线程在自己的工作内存中对共享变量的修改,另外一个线程不能立即看到 。

乱序性

为了优化性能,CPU有时候会改变程序中语句的先后顺序,但基本的程序逻辑不受影响。

非原子性

线程切换带来的非原子性问题,A线程执行时,被切换到B线程执行,之后再A线程执行。 如果解决?加锁,如果只是++的话,JUC并发包下的原子类也可以。

JMM(java内存模型)

java内存模型规定了所有的变量都存储在主内存中,每个线程还有自己的工作内存。线程先将主内存中的共享变量复制到自己的工作内存中去,在自己的工作内存中处理数据,再将处理好的结果写入主内存。

volatile关键字:保证可见性、禁止指令重排序

一旦共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,
1.保证了一个线程修改了此变量,其他线程会立即可见(通过《缓存一致性协议》),保证可见性。
2.禁止指令重排序
3.但是volitile不能保证原子性

CAS机制 (Conpare And Swap 比较并交换)

该算法采用自旋的思想,是一种轻量级锁机制。是(不加锁)乐观锁的实现。

线程先从主内存中获取共享变量复制到工作内存中作为预估值,再处理共享变量,得出结果。此时将线程中的预估值与主内存的值进行比较:
1.如果一样,证明没有其他线程干扰,将结果写入主内存。
2.如果不一样,重新获取预估值,重新进行计算结果,再次进行比较…

CAS缺陷:
由于CAS实现的是乐观锁,他会以自旋的方式不断的进行尝试,而不会像synchronized进行线程阻塞,当大量的线程自旋时,容易把CPU跑满。

原子类的实现是volatile +CAS机制。原子类适合在低并发的情况下使用。

CAS会产生ABA问题

就是一个线程预估值为A,来一个线程将内存值改为B,再有一个线程将内存值又改为A。就不确定内存中的值是否其他线程进行干扰过了。
解决方案:
使用有版本号的原子类AtomicABA 根据版本号来解决问题

java中锁的分类

乐观锁、悲观锁

乐观锁: 它乐观认为对同一个数据的并发操作不会产生线程安全问题,不加锁,它会采用自选的方式,不断的尝试更新数据
悲观锁: 它悲观的认为对同一个数据的并发操作会产生线程安全问题,所以需要加锁进行干预
乐观锁适合“读多写少”的场景,悲观锁适合“读少写多”的场景

可重入锁

就是一个加锁的方法可以调用进入另一个加锁的方法中去,两个方法可以共用同一把锁。可以在一定程度上避免死锁。

你可能感兴趣的:(javaEE系列专栏,面试,java,多线程,并发编程)