线程组:ThreadGroup类
在JDK1.0版本就声明了ThreadGroup类,它表示一个线程的集合。除此之外,线程组也能包含其它的线程组,它是一个树形结构。
ThreadGroup有两种构造方法:
/*构建一个新线程组,父线程是当前正在运行线程的线程组*/
public ThreadGroup(String name)
/*创建一个新线程组。新线程组的父线程组是指定的线程组*/
public ThreadGroup(ThreadGroup parent , String name)
几种常用的方法:
//返回此线程组的名称
public final String getName()
//返回此线程组中活动线程的估计数,结果并不能反映并发活动,建议此方法用于信息目的
public int activeCount()
//中断此线程组中的所有线程。
public final void interrupt()
//判断是否为守护线程组
public final boolean isDaemon():
//更改此线程组的状态为守护线程组
public final void setDaemon(boolean daemon)
关于interrupt()方法:它并不会像stop()方法那样中断一个正在运行的线程,而是将该线程的中断标识位改为true,且线程本身会时不时的检测该中断标识位,以判断该线程是否应该被中断。所以说要是不去检查这个状态该线程就不会执行中断操作,而wait()等阻塞方法会去检查该标识位并且抛出异常。
关于守护线程和用户线程(也称后台线程和普通线程):守护线程是为用户线程服务的,当所有的用户线程结束以后,守护线程会自动结束。比如java中的垃圾回收线程就是很典型的守护线程,当所有线程都结束以后就不会产生垃圾,那么该线程就会自动结束,JVM就可以退出了。
线程池:java中规定了两种线程池的框架:Executor和Fork-Join
为什么会出现线程池?
因为Java线程的创建与销毁需要一定的开销,如果我们为每一个任务创建一个新线程来执行,这些线程的创建与销毁将消耗大量的计算资源。同时,为每一个任务创建一个新线程来执行,这种策略可能会使处于高负荷状态的应用最终崩溃。
线程池的作用:
-
降低资源消耗:通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
-
提高响应速度:当任务到达时,任务可以不需要等到线程创建就能立即执行。
-
提高线程的可管理性: 可以获得线程池中的线程的当前状态。
Executor框架:
Executor是一个接口,是Executor框架的基础,它将任务的执行与提交分离
ThreadPoolExecutor是线程池的核心实现类,用来执行被提交的任务
ThreadPoolExecutor的组件构成:
-
corePool:核心线程池的大小
-
maximumPool:最大线程池的大小
-
BlockingQueue:用来暂时保存任务的工作队列
-
RejectedExecutionHandler:当ThreadPoolExecutor已经关闭或ThreadPoolExecutor已经饱和时(达到了最大线程池的大小且工作队列已满),execute()方法将要调用的handler。
有四种任务拒绝类型:
处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。
- 调用AbrotPolicy()方法,直接抛出异常
- 调用DiscardPolicy()方法,把新添加的任务线程默默丢弃掉
- 调用CallerRunsPolicy()方法,它直接在 execute() 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务.
- 调用DiscardOldestPolicy()方法,它将抛弃等待最久的线程并加入当前线程
Executor可创建四种类型的线程池:
-
FixedThreadPool:有确定的核心线程数,即固定长度的线程池
-
SingleThreadPool:是使用单个线程工作的线程池,相当于FixedThreadPool的参数设置为1时的线程池
-
CachedThreadPool:无核心线程,非核心线程数无上限,它只传递任务,不保存。
-
ScheduledThreadPool:是基于线程池设计的定时任务类,,每个调度任务都会分配到线程池中的一个线程去执行,也就是说,任务是并发执行,互不影响。
Executor框架参考连接:
https://www.cnblogs.com/study-everyday/archive/2017/04/20/6737428.html
Fork-Join框架:
是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架,是一种分治编程,适用于计算量无法评估但可以分解的任务。
ForkJoinTask: 我们要使用ForkJoin框架,必须首先创建一个ForkJoin任务。它提供在任务中执行fork()和join的操作机制,通常我们不直接继承ForkjoinTask类,只需要直接继承其子类。Fork-Join框架提供了两个子类:
- RecursiveAction:用于没有返回结果的任务
- RecursiveTask:用于有返回结果的任务
ForkJoinPool:task要通过ForkJoinPool来执行。