马来西亚做公路投标网站,设计网页多少钱,五莲县财源建设网站,番禺区住房和建设局网站为什么需要线程池 我们有两种常见的创建线程的方法#xff0c;一种是继承Thread类#xff0c;一种是实现Runnable的接口#xff0c;Thread类其实也是实现了Runnable接口。但是我们创建这两种线程在运行结束后都会被虚拟机销毁#xff0c;如果线程数量多的话#xff0c;频繁… 为什么需要线程池 我们有两种常见的创建线程的方法一种是继承Thread类一种是实现Runnable的接口Thread类其实也是实现了Runnable接口。但是我们创建这两种线程在运行结束后都会被虚拟机销毁如果线程数量多的话频繁的创建和销毁线程会大大浪费时间和效率更重要的是浪费内存。那么有没有一种方法能让线程运行完后不立即销毁而是让线程重复使用继续执行其他的任务哪 这就是线程池的由来很好的解决线程的重复利用避免重复开销。 线程池的优点 1、线程是稀缺资源使用线程池可以减少创建和销毁线程的次数每个工作线程都可以重复使用。 2、可以根据系统的承受能力调整线程池中工作线程的数量防止因为消耗过多内存导致服务器崩溃。 线程池的风险 虽然线程池是构建多线程应用程序的强大机制但使用它并不是没有风险的。用线程池构建的应用程序容易遭受任何其它多线程应用程序容易遭受的所有并发风险诸如同步错误和死锁它还容易遭受特定于线程池的少数其它风险诸如与池有关的死锁、资源不足和线程泄漏。 1.死锁 任何多线程应用程序都有死锁风险。当一组进程或线程中的每一个都在等待一个只有该组中另一个进程才能引起的事件时我们就说这组进程或线程 死锁了。死锁的最简单情形是线程 A 持有对象 X 的独占锁并且在等待对象 Y 的锁而线程 B 持有对象 Y 的独占锁却在等待对象 X 的锁。除非有某种方法来打破对锁的等待Java 锁定不支持这种方法否则死锁的线程将永远等下去。 2.资源不足 线程池的一个优点在于相对于其它替代调度机制有些我们已经讨论过而言它们通常执行得很好。但只有恰当地调整了线程池大小时才是这样的。 线程消耗包括内存和其它系统资源在内的大量资源。除了 Thread 对象所需的内存之外每个线程都需要两个可能很大的执行调用堆栈。除此以外JVM 可能会为每个 Java 线程创建一个本机线程这些本机线程将消耗额外的系统资源。最后虽然线程之间切换的调度开销很小但如果有很多线程环境切换也可能严重地影响程序的性能。 如果线程池太大那么被那些线程消耗的资源可能严重地影响系统性能。在线程之间进行切换将会浪费时间而且使用超出比您实际需要的线程可能会引起资源匮乏问题因为池线程正在消耗一些资源而这些资源可能会被其它任务更有效地利用。 除了线程自身所使用的资源以外服务请求时所做的工作可能需要其它资源例如 JDBC 连接、套接字或文件这些也都是有限资源有太多的并发请求也可能引起失效例如不能分配 JDBC 连接。 3.并发错误 线程池和其它排队机制依靠使用 wait 和 notify 方法这两个方法都难于使用。如果编码不正确那么可能丢失通知导致线程保持空闲状态尽管队列中有工作要处理。使用这些方法时必须格外小心即便是专家也可能在它们上面出错。而最好使用现有的、已经知道能工作的实现例如在 util.concurrent 包。 4.线程泄漏 各种类型的线程池中一个严重的风险是线程泄漏当从池中除去一个线程以执行一项任务而在任务完成后该线程却没有返回池时会发生这种情况。发生线程泄漏的一种情形出现在任务抛出一个 RuntimeException 或一个 Error 时。 如果池类没有捕捉到它们那么线程只会退出而线程池的大小将会永久减少一个。当这种情况发生的次数足够多时线程池最终就为空而且系统将停止因为没有可用的线程来处理任务。 5.请求过载 仅仅是请求就压垮了服务器这种情况是可能的。在这种情形下我们可能不想将每个到来的请求都排队到我们的工作队列因为排在队列中等待执行的任务可能会消耗太多的系统资源并引起资源缺乏。在这种情形下决定如何做取决于您自己在某些情况下您可以简单地抛弃请求依靠更高级别的协议稍后重试请求您也可以用一个指出服务器暂时很忙的响应来拒绝请求。 线程池的实现原理 线程池 1.线程池状态 线程池和线程一样拥有自己的状态在ThreadPoolExecutor类中定义了一个volatile变量runState来表示线程池的状态线程池有四种状态分别为RUNNING、SHURDOWN、STOP、TERMINATED。 线程池创建后处于RUNNING状态。 调用shutdown后处于SHUTDOWN状态线程池不能接受新的任务会等待缓冲队列的任务完成。 调用shutdownNow后处于STOP状态线程池不能接受新的任务并尝试终止正在执行的任务。 当线程池处于SHUTDOWN或STOP状态并且所有工作线程已经销毁任务缓存队列已经清空或执行结束后线程池被设置为TERMINATED状态。 线程池原理预先启动一些线程线程无限循环从任务队列中获取一个任务进行执行直到线程池被关闭。如果某个线程因为执行某个任务发生异常而终止那么重新创建一个新的线程而已如此反复。 2.线程池的处理流程 1、判断线程池里的核心线程是否都在执行任务如果不是核心线程空闲或者还有核心线程没有被创建则创建一个新的工作线程来执行任务。如果核心线程都在执行任务则进入下个流程。 2、线程池判断工作队列是否已满如果工作队列没有满则将新提交的任务存储在这个工作队列里。如果工作队列满了则进入下个流程。 3、判断线程池里的线程是否都处于工作状态如果没有则创建一个新的工作线程来执行任务。如果已经满了则交给饱和策略来处理这个任务。 配置线程池大小配置 一般需要根据任务的类型来配置线程池大小 如果是CPU密集型任务就需要尽量压榨CPU参考值可以设为 NCPU1 如果是IO密集型任务参考值可以设置为2*NCPU 当然这只是一个参考值具体的设置还需要根据实际情况进行调整比如可以先将线程池大小设置为参考值再观察任务运行情况和系统负载、资源利用率来进行适当调整。 Java提供的四种线程池实现 1newCachedThreadPool创建一个可缓存线程池如果线程池长度超过处理需要可灵活回收空闲线程若无可回收则新建线程。 2newFixedThreadPool 创建一个定长线程池可控制线程最大并发数超出的线程会在队列中等待。 3newScheduledThreadPool 创建一个定长线程池支持定时及周期性任务执行。 4newSingleThreadExecutor 创建一个单线程化的线程池它只会用唯一的工作线程来执行任务保证所有任务按照指定顺序FIFO, LIFO, 优先级执行。 以上就是线程池的详细介绍后续将详细讲解四种线程池的具体实现。 你可能也喜欢: Java多线程系列(二)线程的五大状态以及线程之间的通信与协作Java多线程系列(七)并发容器的原理7大并发容器详解、及使用场景Java多线程系列(一)最全面的Java多线程学习概述Java多线程系列六深入详解Synchronized同步锁的底层实现 Java多线程系列十源码剖析AQS的实现原理 Java多线程系列(四)4种常用Java线程锁的特点性能比较、使用场景