JDK版本为8

ThreadPoolExecutor有几个参数?

有6个,分别是:

  • corePoolSize,线程池中的线程数(这个数包含空闲线程,除非allowCoreThreadTimeOut设置为true)
  • maximumPoolSize,线程池的最大线程数
  • keepAliveTime,线程存活保持时间
  • workQueue,任务队列
  • threadFactory,线程工厂
  • handler,线程饱和策略

具体参考JDK线程池-概述

Executors工具类有哪几种构造线程池的方法?

有5分钟,分别是:

newFixedThreadPool,创建一个固定线程数的线程池

  • 它是一种固定大小的线程池;
  • corePoolSize和maximunPoolSize都为用户设定的线程数量nThreads;
  • keepAliveTime为0,意味着一旦有多余的空闲线程,就会被立即停止掉;
  • 阻塞队列采用了LinkedBlockingQueue,它是一个无界队列;由于阻塞队列是一个无界队列,因此永远不可能拒绝任务。

newCachedThreadPool

  • 它是一个可以无限扩大的线程池;
  • 它比较适合处理执行时间比较小的任务;
  • corePoolSize为0,maximumPoolSize为无限大,意味着线程数量可以无限大;
  • keepAliveTime为60S,意味着线程空闲时间超过60S就会被杀死;
  • 采用SynchronousQueue装等待的任务,这个阻塞队列没有存储空间,这意味着只要有请求到来,就必须要找到一条工作线程处理他,如果当前没有空闲的线程,那么就会再创建一条新的线程。

newScheduledThreadPool

  • 用来处理延时任务或者定时任务

newSingleThreadExecutor

  • 它只会创建一条工作线程处理任务;
  • 采用的阻塞队列为LinkedBlockingQueue。

newWorkStealingPool

  • 创建一个带并行级别的线程池,并行级别决定了同一时刻最多有多少个线程在执行,默认为当前系统的CPU个数。

Java中的锁,synchronized和lock有什么区别?分别有什么应用场景?

  • synchronized是关键字,Lock是接口
  • synchronized是JVM释放锁,Lock需要手动释放锁
  • synchronized可重入,不可中断,非公平,Lock可重入,可中断,可公平

轻量级锁?

  • synchronized锁的状态有3种,偏向锁,轻量级锁,重量级锁
  • 偏向锁是指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁。降低获取锁的代价
  • 轻量级锁是指当锁是偏向锁的时候,被另一个线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,提高性能
  • 重量级锁是指当锁为轻量级锁的时候,另一个线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让其他申请的线程进入阻塞,性能降低。

无锁线程安全?

  • final,定义为final的变量天然线程安全
  • Automic类,利用硬件提供的CAS功能

Java内存模型?

  • 主内存,JMM规定所有变量都存储在主内存,主内存是共享内存区域,所有线程都可以访问
  • 工作内存,JVM为每个线程创建的内存空间,线程对变量的操作(读取赋值等)必须在工作内存中进行,首先要将变量从主内存拷贝的自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写回主内存,不能直接操作主内存中的变量,工作内存中存储着主内存中的变量副本拷贝

volatile关键字作用?

  • 内存可见性,意思就是如果一个变量定义为volatile,如果一个线程改变了该变量值,其他线程会直接得到变量最新值,一般用在状态位的控制。
  • 禁止指令重排序优化

happen before原则?

  • 程序顺序原则,即在一个线程内必须保证语义串行性,也就是说按照代码顺序执行。
  • 锁规则,解锁(unlock)操作必然发生在后续的同一个锁的加锁(lock)之前,也就是说,如果对于一个锁解锁后,再加锁,那么加锁的动作必须在解锁动作之后(同一个锁)。
  • volatile规则,volatile变量的写,先发生于读,这保证了volatile变量的可见性,简单的理解就是,volatile变量在每次被线程访问时,都强迫从主内存中读该变量的值,而当该变量发生变化时,又会强迫将最新的值刷新到主内存,任何时刻,不同的线程总是能够看到该变量的最新值。
  • 线程启动规则,线程的start()方法先于它的每一个动作,即如果线程A在执行线程B的start方法之前修改了共享变量的值,那么当线程B执行start方法时,线程A对共享变量的修改对线程B可见
  • 传递性,A先于B ,B先于C 那么A必然先于C
  • 线程终止规则,线程的所有操作先于线程的终结,Thread.join()方法的作用是等待当前执行的线程终止。假设在线程B终止之前,修改了共享变量,线程A从线程B的join方法成功返回后,线程B对共享变量的修改将对线程A可见。
  • 线程中断规则,对线程 interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测线程是否中断。
  • 对象终结规则,对象的构造函数执行,结束先于finalize()方法