创建线程

  1. new Thread(()->{
  2. //todo
  3. }).start();

启动流程:
创建线程start()->start0()->JVM_ENTRYThread::start->os::create_thread``os::create_thread->回调JavaThread::run->run()

Thread状态转换

Thread有五种状态: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMNATED
new:新创建的线程,处于等待状态
runnable:可运行状态,其包括了ready和running两个状态,当调用了start方法后,线程就会处于ready状态,等待操作系统分配时间片,分配后则进入running状态。当调用yield方法时,只是谦让的允许当前线程让出CPU。让出与否由操作系统的决定。
timed_waiting:指定时间内让出CPU资源,在这段时间内线程不会执行。可由Thread.sleep``Object.wait``Thread.join``LockSupport.parkNanos``LockSupport.parkUntil触发。
waiting:可被唤醒的等待状态,可以通过synchronized获得锁,调用wait方法进入等待状态,最后通过notify或notifyall唤醒。
blocked:发送锁竞争的状态时未获得的线程会处于挂起状态。
terminated:终止状态,流程结束或发生异常。

Thread方法使用

start

启动方法

yield

让出CPU,但通过操作系统调度。用于按照优先级保证重要线程执行。

wait/notify

这是一对方法,wait用于挂起线程,notify用于唤醒线程。

join

join让线程进入wait,当线程执行完毕后,再执行notify。说人话就是把这个线程插进执行队列中,先让他执行然后再唤醒别的线程。join是一个synchronized方法,里面调用了wait方法,让当前持有同步锁的线程等待,当子线程完成后再唤醒。

线程池

  1. ThreadPoolExecutor pool =
  2. new ThreadPoolExecutor(10,10,0L,TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(10));
  3. pool.execute(()->{
  4. //to do
  5. });
  6. pool.shutdown();

线程池状态

running:运行状态,接受新任务并处理队列中的任务
shutdown:关闭状态(调用shutdown方法),不接受新任务但处理队列中的任务
stop:停止状态(调用shutdownNow方法,不接受新任务也不处理任务,中断正在处理的任务
tidying:所有任务终止,然后调用terminated()方法进入terminated状态
terminated:终止状态。
在ThreadPoolExecutor的实现类中,使用AtomicInteger类型的ctl记录线程池状态和线程数量。高三位记录状态,低29位存储线程数量。

execute

先比较核心线程数,小于则进入到任务执行队列,否则判断线程池是否为运行状态,是则把不能执行的线程放入线程队列中。然后再重新判断线程是否运行,否则执行拒绝策略。最后再次尝试添加任务执行,添加失败会进行拒绝。

常见四种线程池

newFixedThreadPool

  1. new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue())

创建一个大小固定可重复使用的线程池,通过LinkedBlockQueue无界阻塞队列存放等待线程。
随着线程任务不能执行无限堆积,可能导致内存耗尽。

newSingleThreadExecutor

  1. new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())

创建一个corePoolSize=1的线程池,如果出现意外终止再创建一个。
同样因为使用无界队列存放等待执行进程,可能导致内存耗尽。

newCachedThreadPool

  1. new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>())

使用SynchronousQueue存储任务队列,有任务就会调用线程生成,保证任务执行。
如果线程任务比较耗时又大量创建会导致oom。

newScheduledThreadPool

  1. public ScheduledThreadPoolExecutor(int corePoolSize)
  2. { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
  3. new ScheduledThreadPoolExecutor.DelayedWorkQueue()); }

可以延期定时执行,无限大小,调用方法有:scheduleAtFixedRate/scheduleWithFixedDelay,用于选择延迟模式。因为是无限容量线程池,同样有可能oom。

线程池的使用场景

主要是把串行的请求压缩为并行。

线程池的监控

image.png

重写方式监控

通过继承ThreadPoolExecutor类重写方法进行监控。

基于JVMTI方式监控

JVMTI是JVM提供的native编程接口,提供了性能分析、debug、内存管理、线程分析等功能。