多线程问题与解答

收集常见的问题,之后或许用获得java

  1. 线程池的原理,为何要建立线程池?建立线程池的方式? 答:当向线程池提交一个任务的时候。
  • 先看线程池中的核心线程是否有空闲的,若是有建立一个工做线程来执行任务。若是核心线程都在工做,那么进入下一步
  • 判断任务队列是否满了,若是任务队列未满,则把任务存储到任务队列,执行下一步。若是满了,执行拒绝策略。
  • 添加到任务队列以后,再判断核心线程是否有空闲的,若是没有空闲的,那么尝试建立新的非核心线程执行任务。

在实际的生产环境中,线程的数量必须获得控制,盲目的大量建立线程对系统性能是有伤害的,合理使用线程好处:程序员

  • 减小在建立和销毁现场上所消耗的时间和系统资源
  • 提升响应速度,无需建立能够直接运行
  • 提升线程的可管理性。使用线程池能够进行统一分配,调优和监控,可是要作到合理利用线程池,必须对其原理了如指掌。

建立线程池的方式:面试

  • Executors框架,有可能致使OOM异常
  • 手动建立线程池,咱们更明白线程池的参数,方便调优

参考:多线程之线程池(六)数据库

  1. 线程的生命周期,何时会出现僵死进程? 线程是轻量级的进程,进程能够说是线程的容器。
    image

参考:多线程之并发基础-线程状态与操做(三)编程

  1. 说说线程安全问题,什么是实现线程安全,如何实现线程安全? 并发编程中最常出现的情形就是多个线程共享一个资源,这些共享的资源极可能致使错误或者数据不一致的情形,须要想办法来解决这种问题。线程安全是多线程领域的问题,线程安全能够简单理解为一个方法或者一个实例能够在多线程环境中使用而不会出现问题。

线程安全实现方式:数组

  • 互斥同步,加锁,悲观方案,保证共享数据同一时刻只有一个线程访问。,互斥是因,同步是果。
  • 非阻塞同步,CAS,乐观方案,先进行操做,若是没有其余线程也进行操做,那么就操做成功了,若是有其它线程也在操做共享数据,那么再重试。
  • 无同步方案,通常为纯代码,有一些特性,如不依赖堆上的公用系统资源

参考:Java高效并发(九)安全

  1. synchronized便可修饰非静态方式,也可修饰静态方法,还可修饰代码块,有何区别? 答:synchronized修饰非静态同步方法时,锁住的是当前实例;synchronized修饰静态同步方法时,锁住的是该类的Class对象;synchronized修饰静态代码块时,锁住的是synchronized关键字后面括号内的对象。bash

  2. 建立线程池有哪几个核心参数? 如何合理配置线程池的大小?多线程

  • corePoolSize: 线程池的基本大小。当提交一个任务的时候,线程池就会建立一个新的线程执行任务,即便核心线程池中有空闲线程,也会新建,直到线程池中的数量等于corePoolSize就再也不建立。若是调用了线程池的prestartAllCoreThreads()方法,线程池会提早建立并启动全部的线程。
  • maximumPoolSize:线程池容许建立的最大线程数。当使用无界队列的时候,这个参数就没什么效果了。
  • keepAliveTime:线程池的工做线程空闲之后,保持存活的时间,若是任务多,而且任务执行时间段,能够调大时间,提升线程的利用率。
  • unit 保活时间的单位
  • workQueue: 任务队列,用于保持或等待执行的任务阻塞队列。有以下队列可供选择:
    • ArrayBlockingQueue: 基于数组结构的有界队列,此队列按FIFO原则对元素进行排序
    • LinkedBlockingQueue: 基于链表的阻塞队列,FIFO原则,吞吐量一般高于ArrayBlockingQueue.
    • SynchronousQueue: 不存储元素的阻塞队列。每一个插入必需要等到另外一个线程调用移除操做。
    • PriorityBlockingQueue: 具备优先级的无阻塞队列
  • threadFactory:用于设置建立线程的工厂。
  • handler:拒绝策略,当队列线程池都满了,必须采用一种策略来处理还要提交的任务。在实际应用中,咱们能够将信息记录到日志,来分析系统的负载和任务丢失状况JDK中提供了4中策略:
    • AbortPolicy: 直接抛出异常。 默认的策略
    • CallerRunsPolicy: 只用调用者所在的线程来运行任务
    • DiscardOldestPolicy: 丢弃队列中最老的一我的任务,并执行当前任务。
    • DiscardPolicy: 直接丢弃新进来的任务

线程池中线程的数量过大和太小都没法使系统的性能发挥到最优,肯定线程池的大小能够考虑下面的角度:并发

  • 任务性质:CPU密集,IO密集,和混合密集
  • 任务执行时间:长,中,低
  • 任务优先级:高,中,低
  • 任务的依赖性:是否依赖其它资源,如数据库链接
  • 建议使用有界队列,防止撑爆内存

CPU密集型:线程数=按照核数或者核数+1
IO密集型: 线程数=CPU核数 * (1 + 平均等待时间/平均工做时间)

参考:多线程之线程池(六)

  1. volatile、ThreadLocal的使用场景和原理? JMM中主要是围绕并发过程当中如何处理原子性,可见性和有序性三个特性来创建的。最终能够保证线程安全性.

一个变量定义为volatile以后,它将具备两种特性:

  • 保证次变了对全部线程的可见性,一条线程修改了这个值,新值对其它线程是能够当即得知的。
  • 禁止指令重排优化。

Synchronized保证了原子性,可见性与有序性,它的工做时对同步的代码块加锁,使得每次只有一个线程进入代码块,从而保证线程安全。synchronized反应到字节码层面就是monitorenter与monitorexit.

Volatile适合作什么? 适合作标量,当一个线程对某个变量进行读写操做,而其它线程仅仅进行读操做的时候,是能够保证volatile的正确性的。以下:

volatile bool stopped;
public void stop(){
    stopped = true
}

while(!stoppped){
    // 执行操做
}
复制代码

参考:多线程之volatile与synchronized(二)

  1. ThreadLocal何时会出现OOM的状况?为何? 答:当一个线程调用ThreadLocal的set方法设置变量时候,当前线程的ThreadLocalMap里面就会存放一个记录,这个记录的key为ThreadLocal的引用,value则为设置的值。若是当前线程一直存在而没有调用ThreadLocal的remove方法,而且这时候其它地方仍是有对ThreadLocal的引用,则当前线程的ThreadLocalMap变量里面会存在ThreadLocal变量的引用和value对象的引用是不会被释放的,这就会形成内存泄露的。

参考:使用ThreadLocal不当可能会致使内存泄露 借ThreadLocal出现OOM内存溢出问题再谈弱引用WeakReference

  1. 线程池的状态有哪些?
  • Running: 能接受新的任务,而且能处理阻塞队列中的任务
  • Shutdown: 再也不接受新的任务,可是能处理存量任务
  • ShutdownNow: 再也不接受新的任务,也不处理存量任务
  • Tidying: 全部任务都已经终止
  • Terminated: terminated()方法执行以后进入此状态
// ThreadPoolExecutor内部代码
    private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;
复制代码

image.png

最后

持续更新,多线程相关问题

题目参考

相关文章
相关标签/搜索