- 线程组
- 线程的未捕捉异样与监控
- 线程池
线程组
线程组 (ThreadGroup) 能够用来示意一系列类似或者相干的线程汇合。
一个线程组能够蕴含多个线程和线程组,一个线程组蕴含另外的线程组那么这个线程组被称为另外这些线程组的父线程组,如过一个线程没有被关联线程组,那么这个线程就属于其父线程所属的线程组,java 虚拟机在创立 main 线程的时候会为其指定一个线程组,所以 java 中任何一个线程都有与之关联的线程组,咱们为您能够通过 Thread.getThreadGroup()来获取以后线程所关联的线程组。
线程的未捕捉异样与监控
当线程在 run 的时候呈现未捕捉的异样,那么导致 run 办法退出,且相应的线程也将会终止。对于这种状况咱们能够在线程启动之前为其关联一个 UncaughtExceptionHandler
,当线程呈现未捕捉异样抛出的时候,线程会在退出之前调用UncaughtExceptionHandler.UncaughtException(Thread t, Throwable e)
办法,咱们能够在这个办法中进行相应的日志解决,或者从新创立一个线程来代替这个线程。
public class UncaughtExceptionDemo {
static class MyExceptionHandler implements Thread.UncaughtExceptionHandler{
@Override
public void uncaughtException(Thread t, Throwable e) {System.out.println(t.getName()+"线程抛出了异样");
MyThread thread = new MyThread();
thread.setName("B");
thread.setUncaughtExceptionHandler(new MyExceptionHandler());
thread.start();}
}
static class MyThread extends Thread{
@Override
public void run() {if ("A".equals(Thread.currentThread().getName())){throw new BusinessException("出现异常:"+Thread.currentThread().getName());
}
System.out.println(Thread.currentThread().getName());
}
}
static class BusinessException extends RuntimeException{public BusinessException(String message) {System.out.println(message);
}
}
public static void main(String[] args) {MyThread myThread = new MyThread();
myThread.setName("A");
myThread.setUncaughtExceptionHandler(new MyExceptionHandler());
myThread.start();}
}
=========== 后果 ============
出现异常:A
A 线程抛出了异样
B
线程池
应用线程池的益处
- 升高资源耗费: 线程池中存有能够复用的线程,能够缩小线程 创立 - 销毁 所带来的性能耗费
- 进步线程响应速度: 线程池中的的线程间接响应工作,而不是响应工作后还要创立线程
- 有利于线程的治理
线程池中各个参数的含意
线程池中各个组件的职责及流程
- 线程池管理器,负责线程池的创立、销毁、增加工作等
- 工作线程
- 工作队列,用来长期存储工作,能够起到缓冲的作用,因为个别处于并发场景,所以工作队列个别采纳 BlockingQueue 来保障线程平安。
- 工作,工作要求实现对立接口,以便工作线程能够执行和解决
什么是回绝策略
- 线程池调用 shutdown 后,线程池会期待以后线程池中的所有线程执行完,但不会接管新的工作。
- 外围线程池满了 – 工作队列满了 – 线程池达到了最大线程数 – 线程池不会接管新的工作。
常见的几种回绝策略
- DiscardPolicy:会间接漠视新加进来的工作
- DiscardOldestPolicy:会移除队列中的队头工作,将新的工作插到队尾
- AbortPolicy:会抛出一个名为 RejectedExecutionException 的运行时异样,能够在 catch 中重新处理这个工作
- CallerPolicy:有新工作然而线程池没有能力解决时,由提交工作的线程执行。(最欠缺)
常见线程池
-
FixedThreadPool
固定线程数的线程池,外围线程数和最大线程数雷同 new FixedThreadPool(10) – 最开始线程数从 0 开始减少当减少到 10 后就不再减少,有新的工作就放到工作队列当中,当再有新的工作就不会有新的线程产生。
-
CachedThreadPool
线程池中的线程能够有限减少,但不会超过 Integr.MAX\_VALUE(2 ^ 31,简直不会达到)
-
ScheduleThreadPool
周期性执行工作
-
SingleThreadExecutor
只有一个线程来执行工作,然而以后线程出现异常时,线程池会新创建一个线程执行后续工作,益处就是执行的工作是有序的。
-
SingleThreadScheduleExecutor
与 3 及其类似是 ScheduleThreadPool 的一个特例,相当于 new ScheduledThreadPoolExecutor(1)
-
ForkJoinPool
罕用于递归场景,例如树遍历
RecursiveTask 类是对 ForkJoinTask 的一个简略的包装,这时咱们重写 compute() 办法,当 n<= 1 时间接返回,当 n>1 就创立递归工作,也就是 f1 和 f2,而后咱们用 fork() 办法决裂工作并别离执行最初在 return 的时候,应用 join() 办法把后果汇总,这样就实现了工作的决裂和汇总。
class Fibonacci extends RecursiveTask<Integer> { int n; public Fibonacci(int n) {this.n = n;} @Override public Integer compute() {if (n <= 1) {return n;} Fibonacci f1 = new Fibonacci(n - 1); f1.fork(); Fibonacci f2 = new Fibonacci(n - 2); f2.fork(); return f1.join() + f2.join(); } } public static void main(String[] args){ForkJoinPool forkJoinPool = new ForkJoinPool(); for (int i = 0; i < 10; i++) {ForkJoinTask task = forkJoinPool.submit(new Fibonacci(i)); System.out.println(task.get()); } }
为什么不倡议应用 Executors 创立 线程池
下图是各个线程池对应应用的阻塞队列
-
FixedThreadPool 和 SingleThreadExecutor
因为 LinkBlockingQueue 容量简直是无限大的,如果工作的生产速度远超过工作生产速度会导致队列中沉积大量的工作有可能会导致内存溢出。
-
CatchedThreadPool
当工作较多的时候,线程池会无限度的新建线程,最终可能导致操作系统无奈新建线程或者是内存溢出
-
ScheduleThreadPool 和 SingleThreadScheduleExecutor
DelayedWorkQueue 也是一个无界队列,如果队列中存在大量的工作同样可能内存溢出。
如何正确敞开线程池
-
shutdown
调用这个办法后,线程池不会立刻进行而是等队列中的所有工作处理完毕后才会彻底敞开,如果此时还有新的工作提交将会被回绝。
-
shutdownNow
立刻终止线程池中的所有操作,不平安,不倡议应用
-
isShutdown
判断是否执行了 shutdown 办法,此时可能线程池还在执行残余工作。
-
isTerminated
是否彻底终止了,即执行了 shoutdown+ 残余工作被执行完 或者 执行了 shutdownNow
-
awaitTermination
awaitTermination(10) – 期待 10 秒,10 秒内工作都执行结束 返回 true,10 秒内并未执行结束 返回 false
线程池监控
ThreadPoolExecutor 提供的线程池监控相干办法
办法 | 用处 |
---|---|
getPoolSize() | 获取以后线程池大小 |
getQueue() | 返回工作队列实例,通过该实例可获取工作队列的以后大小 |
getLargestPoolSize() | 获取工作者线程数已经达到的最大数,该数值有助于确认线程池的最大大小设置是否正当 |
getActiveCount() | 获取线程池中以后正在执行工作的工作者线程数(近似值) |
getTaskCount() | 获取线程池到目前为止所接管到的工作数(近似值) |
getCompletedTaskCount() | 获取线程池到目前为止曾经处理完毕的工作数(近似值) |