江苏企业建设网站公司,网站建设洪塔,开发网站有什么用,桥西企业做网站线程池 文章目录 线程池一#xff0c;前言二#xff0c;线程池三#xff0c;参数四#xff0c;线程池的实现原理5.线程池的使用案例(自定义线程池)6.使用Executors 创建常见的功能线程池1.固定大小线程池2.定时线程3.可缓存线程池4.单线程化线程池 一#xff0c;前言
虽然…线程池 文章目录 线程池一前言二线程池三参数四线程池的实现原理5.线程池的使用案例(自定义线程池)6.使用Executors 创建常见的功能线程池1.固定大小线程池2.定时线程3.可缓存线程池4.单线程化线程池 一前言
虽然线程给我们程序带来了更高的执行效率但是线程不是创建的越多越好那么线程创建的过多会带来什么问题呢 首先线程的创建和销毁都是很耗时很浪费性能的操作 new三五个Thread还好我需要一千个线程呢 线程之间频繁的进行上下文切换增加系统的负载 为了解决上述问题线程池诞生了线程池的核心思想就是线程复用。
也就是说线程用完后不销毁放到池子里等着新任务的到来反复利用N个线程来执行所有新老任务。这带来的开销只会是那N个线程的创建而不是每来一个请求都带来一个线程的从生到死的过程。
二线程池
概念
线程池是一种多线程处理形式处理过程中将任务添加到队列然后在创建线程后自动启动这些任务。 线程池是一种线程复用的技术可以有效地控制线程的数量减少线程创建和销毁带来的开销提高系统响应速度并方便线程管理。官方
简单来说线程池就是提前创建好一批线程当有任务的时候从池子中取出一个线程去执行该任务执行结束后再把线程放回池子中以备循环使用。
三参数
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize, long keepAliveTime,TimeUnit unit,BlockingQueueRunnable workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {
}参数解释
corePoolSize核心线程数 线程池在完成初始化之后默认情况下线程池中不会有任何线程线程池会等有任务来的时候 再去创建线程。核心线程创建出来后即使超出了线程保持的存活时间配置也不会销毁核心线程 只要创建就永驻了就等着新任务进来进行处理。 maximumPoolSize最大线程数 核心线程忙不过来且任务存储队列满了的情况下还有新任务进来的话就会继续开辟线程但是 也不是任意的开辟线程数量线程数包含核心线程达到最大线程数后就不会产生新线程了 就会执行拒绝策略。 keepAliveTime线程保持的存活时间 如果线程池当前的线程数多于核心线程数那么如果多余的线程空闲时间超过线程保持的存活时 间那么这些多余的线程超出核心线程数的那些线程就会被回收。 unit线程保持的存活时间单位 比如TimeUnit.MILLISECONDS、TimeUnit.SECONDS workQueue任务存储队列 核心线程数满了后还有任务继续提交到线程池的话就先进入任务存储队列。 workQueue通常情况下有如下选择 LinkedBlockingQueue无界队列意味着无限制其实是有限制大小是int的最大值。也可以 自定义大小。 ArrayBlockingQueue有界队列可以自定义大小到了阈值就开启新线程不会超过最大线 程数。 SynchronousQueue Executors.newCachedThreadPool();默认使用的队列。 一般都采取无界队列因为他也可以设置大小可以取代有界队列。 threadFactory当线程池需要新的线程时会用threadFactory来生成新的线程 默认采用的是 DefaultThreadFactory 主要负责创建线程。 newThread() 方法。创建出来的 线程都在同一个线程组且优先级也是一样的。 handler拒绝策略任务量超出线程池的配置限制或执行shutdown还在继续提交任务的话会执行handler 的逻辑。 默认采用的是 AbortPolicy 遇到上面的情况线程池将直接采取直接拒绝策略也就是直接抛 出异常。 RejectedExecutionException 四种内置的拒绝策略
1. AbortPolicy默认直接抛出RejectedExecutionException异常阻止系统正常运行。
2. CallerRunsPolicy由调用线程提交任务的线程执行被拒绝的任务。这样做可以降低新任务
的提交速度但可能会影响整体性能。
3. DiscardPolicy默默地丢弃被拒绝的任务不做任何处理。
4. DiscardOldestPolicy丢弃最早被放入队列的任务然后尝试重新提交被拒绝的任务。//自定义拒绝策略实现RejectedExecutionHandler接口并重写rejectedExecution方法来定义自
己的处理逻辑四线程池的实现原理 从图中我们可以看到完整的执行流程
线程提交到线程池判断核心线程池是否已经达到设定的数量如果没有达到则直接创建线程执行任务如果达到了则放在队列中等待执行如果队列已经满了则判断线程的数量是否已经达到设定的最大值如果达到了则直接执行拒绝策略如果没有达到则创建线程执行任务。
5.线程池的使用案例(自定义线程池)
import java.util.concurrent.*;public class ThreadPoolExample {public static void main(String[] args) {// 创建线程池ExecutorService executorService new ThreadPoolExecutor(2, //两个核心线程数4, //最大线程数60, // 线程保持的存活时间TimeUnit.SECONDS,//指定了 keepAliveTime 的单位为秒new ArrayBlockingQueue(10),//最多可以在这个队列中排队 10 个任务Executors.defaultThreadFactory(),// Java 提供的默认线程工厂来创建新线程new ThreadPoolExecutor.AbortPolicy());//拒绝策略// 提交任务for (int i 0; i 10; i) {executorService.submit(() - {//submit 方法用于提交一个可执行的任务//() - { ... }表示一个实现了 Runnable 接口的匿名类。大括号内的代码是你希 望在独立线程中执行的逻辑。try {System.out.println(执行任务开始 Thread.currentThread().getName());Thread.sleep(2000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}});}// 关闭线程池executorService.shutdown();}
}//输出结果
执行任务开始 pool-1-thread-1
执行任务开始 pool-1-thread-2
执行任务开始 pool-1-thread-2
执行任务开始 pool-1-thread-1
执行任务开始 pool-1-thread-2
执行任务开始 pool-1-thread-1
执行任务开始 pool-1-thread-2
执行任务开始 pool-1-thread-1
执行任务开始 pool-1-thread-1
执行任务开始 pool-1-thread-2在输出中pool-1-thread-1 和 pool-1-thread-2 中的数字分别代表以下含义
pool-1这是线程池的名称。1 表示这是第一个创建的线程池如果有多个线程池则会以递增的数字命名。thread-1 和 thread-2这些表示线程在该线程池中的编号。它们是按照创建顺序递增的。thread-1 是第一个线程thread-2 是第二个线程依此类推。
因此整个字符串表示该线程池中的具体线程帮助我们识别和调试哪个线程在执行哪个任务。
6.使用Executors 创建常见的功能线程池
Executors为我们封装好了 4 种常见的功能线程池如下
定长线程固定大小FixedThreadPool定时线程ScheduledThreadPool可缓存线程池CachedThreadPool单线程化线程池SingleThreadExecutor
1.固定大小线程池
核心线程数和最大线程数是一样的所以称之为固定线程数。 其他参数配置默认为永不超时0ms无界队列 LinkedBlockingQueue 、默认线程工厂 DefaultThreadFactory 、直接拒绝策略 AbortPolicy 。
public class ThreadPoolTest {public static void main(String[] args) {ExecutorService executorService Executors.newFixedThreadPool(2);for (int i 0; i 10; i) {// 从结果中可以发现线程name永远都是两个。不会有第三个。executorService.execute(() - System.out.println(Thread.currentThread().getName()));}}
}2.定时线程
核心线程数手动传进来最大线程数是Integer.MAX_VALUE最大线程数是内部默认的不可更改。 其他参数配置默认为永不超时0ns带延迟功能的队列 DelayedWorkQueue 、默认线程工厂 DefaultThreadFactory 、直接拒绝策略 AbortPolicy 。
public class ThreadPoolTest {public static void main(String[] args) {ScheduledExecutorService scheduledExecutorService Executors.newSchedul
edThreadPool(2);// 五秒一次scheduledExecutorService.schedule(() - System.out.println(Thread.currentThread().getName()), 5, TimeUnit.SECONDS);// 首次五秒后执行其次每隔1s执行一次scheduledExecutorService.scheduleAtFixedRate(() - System.out.println(Thread.currentThread().getName()), 5, 1, TimeUnit.SECONDS);
}
3.可缓存线程池
他的功能是来个任务我就开辟个线程去处理不会进入队列 SynchronousQueue 队列也不带存储元素 的功能。那这意味着来一亿个请求就会开辟一亿个线程去处理keepAliveTime为60S意味着线程空 闲时间超过60S就会被杀死这就叫带缓存功能的线程池。 核心线程数是0最大线程数是int的最大值内部默认的不可更改。
public class ThreadPoolTest {public static void main(String[] args) {ExecutorService executorService Executors.newCachedThreadPool();for (int i 0; i 10; i) {// 从结果中可以发现线程name有10个。也就是有几个任务就会开辟几个线程。executorService.execute(() -System.out.println(Thread.currentThread().getName()));}}
}4.单线程化线程池
核心线程数和最大线程数是1内部默认的不可更改所以称之为单线程数的线程池。 类似于 Executors.newFixedThreadPool(1); 其他参数配置默认为永不超时0ms无界队列 LinkedBlockingQueue 、默认线程工厂 DefaultThreadFactory 、直接拒绝策略 AbortPolicy 。
public class ThreadPoolTest {public static void main(String[] args) {ExecutorService executorService Executors.newSingleThreadExecutor();for (int i 0; i 10; i) {// 从结果中可以发现线程name永远都是pool-1-thread-1。不会有第二个出现。executorService.execute(() -System.out.println(Thread.currentThread().getName()));}}
}