网站首页 > java教程 正文
我们都知道线程的创建和销毁都是会消耗大量的资源。在大批量并发的场景下,频繁地创建和销毁线程会严重影响系统的性能。所以,通常情况下需要预先创建好几个线程,并且将其集中管理起来,形成一个线程池。在需要用到线程执行的时候,可以从线程池中拿到一个线程直接进行使用,线程的管理则是交给了线程池来管理,这样就可以减少创建和销毁线程所带来的性能影响。
Executors
从Java5开始,JDK提供了Executors来进行线程池的创建;下面就来介绍一下Java为我们提供的线程池都有哪些?
- 创建固定大小的线程池;
ExecutorService cachePool = Executors.newFixedThreadPool(20);
上面这段代码是创建了一个20个固定线程大小的线程池。也就是说这个线程池同时可以运行20个线程。如果超过20个线程同时访问的时候,就会进入到等待队列中,等待线程执行完毕之后,线程池中有空闲线程然后再依次执行线程任务。其优点就是减少了创建线程所带来的开销,缺点则是线程池中的线程数量被限制了,当并发数太高的话会影响整体的系统性能。
- 创建可变大小的线程池
ExecutorService executorService = Executors.newCachedThreadPool();
上面代码创建了一个可以缓存空闲线程60秒的线程池。当有新的线程进入的时候,如果线程池中没有空闲线程可以使用,则创建一个新的线程并且添加到线程池中。这个线程池的大小就是Integer.MAX_VALUE。如果线程超过60秒之内没有执行线程这个线程就会被销毁。这种线程池的优点就是可以根据需求来创建线程,并且对线程进行回收。但是缺点也比较明显,如果线程量超过限制的话就会导致宕机等问题的发生。
- 创建只有一个线程的线程池
ExecutorService oneThreadPool = Executors.newSingleThreadExecutor();
- 创建一个支持定时或者周期性执行任务的线程池
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
ExecutorService
从上面代码中可以看到,通过Executors 创建的线程池都是实现了ExecutorService接口,我们可以通过调用它的execute()方法或者是submit()方法往线程池中提交任务,以便线程池执行完成任务的执行。
下面我们就来介绍一下ExecutorService接口中中的主要方法
- shutdown():异步关闭线程池方法,调用之后,就不能再向线程池中提交线程任务了,但是允许线程池中没有执行完成的任务继续执行。该方法调用之后立即返回,不会阻塞当前线程。
- shutdownNow():立即关闭线程池,调用之后,不但不能往线程池中提交任务 ,而且会取消已经提交到线程等待队列中的线程任务,并且线程池中的所有线程都将会被调用interrupt()方法来尝试中断正在执行中的线程任务。调用之后立即返回结果,不阻塞当前线程。但是由于不能优雅的中断线程,所以也会带来很多意想不到的问题,建议慎用。
- boolean awaitTermination(long timeout, TimeUnit unit):调用这个方法将阻塞当前线程,等待线程池中的任务执行完毕,参数设置为阻塞的时间,以及单位。
- boolean isTerminated():调用了shutdown()方法之后用来判断任务是否已经全部完成。
- submit( task):向线程池中提交一个任务,并且需要线程池的反馈结果。
- void execute(Runnable command):线程池中提交任务,并且不需要线程反馈结果
- boolean isShutdown():返回线程池是否已经关闭
- invokeAll():启动多个线程,在需要并发执行多个任务的情况下进行使用。这些任务要么执行成功,要么因为异常或者是超时被取消。
- invokeAny():启动多个线程,并且相互之间独立的计算一个结果,一旦其中的一个执行成功,就会终止其他线程的执行。
ThreadPoolExecutor
追踪代码会发现,Executors 调用的创建线程的方法内部都是通过调用了ThreadPoolExecutor来实现的。如下图所示。
因此,我们也可以直接通过ThreadPoolExecutor来构建需要的线程池,但是需要了解其中的参数的使用。具体内容如下
- private volatile int corePoolSize; 核心线程数,也就是线程池中最少支持执行的线程数。
- private volatile int maximumPoolSize:最大线程数
- private volatile long keepAliveTime :线程最长空闲时间
- private final BlockingQueue<Runnable> workQueue; 任务队列,不同类型的线程采用的任务队列是不一样的,比较常用的有SynchronousQueue、LinkedBlockingQueue、ArrayBlockingQueue。
- private volatile ThreadFactory threadFactory;用于确定怎么去创建线程池,一般用来确定是否为守护线程,并且设置线程分组、名称、优先级等等。
- private volatile RejectedExecutionHandler handler;拒绝策略,当线程池等待队列达到上限之后,需要提供什么样的处理机制。
ThreadPoolExecutor 使用规则是比较复杂的,如果不能正确地掌握就会带来各种各样的麻烦,简单的可以归纳如下
- 在执行线程数低于核心线程数的情况下来进行线程的创建
- 线程数高于核心线程数的且低于最大线程数的时候,启动线程等待队列来处理线程等待。这个时候就需要更具具体使用的线程队列来判断,如果使用的SynchronousQueue 队列则检查是否有空闲线程,有空闲线程则使用空闲线程来执行任务,反之就需要创建新的线程来执行。如果使用的是LinkedBlockingQueue 队列,新任务就会进入到线程队列进行等待执行操作。这就意味着最大线程数在这种情况下是无效的。因为线程可执行线程不可能超过核心执行线程数,空余线程也将在超过等待时间之后被销毁。
- 线程数达到最大线程数的时候,如果使用的是SynchronousQueue队列,则触发拒绝策略,反之,如果使用LinkedBlockingQueue队列,则会尝试将任务放入到队列中,如果队列满了,就需要执行拒绝策略。
猜你喜欢
- 2024-09-19 Java线程池的四种用法与使用场景(java线程池的原理和实现)
- 2024-09-19 尚学堂百战程序员:Java中的线程池
- 2024-09-19 Java线程池深度揭秘(java线程池入门)
- 2024-09-19 Java线程池(java线程池参数详解)
- 2024-09-19 如何更好的使用JAVA线程池(java中线程池的使用)
- 2024-09-19 史上最详细、最系统、最全面Java线程池解析
- 2024-09-19 好文推荐:深入分析Java线程池的实现原理
- 2024-09-19 Java的线程池是怎么回事?来看看这篇文章吧
- 2024-09-19 Java之线程池(java线程池实战)
- 2024-09-19 Java Web应用调优线程池:没你想的那么复杂
你 发表评论:
欢迎- 最近发表
-
- class版本不兼容错误原因分析(class更新)
- 甲骨文Oracle公司为Java的最新LTS版本做出改进
- 「版本发布」Minecraft Java开发版 1.19.4-pre1 发布
- java svn版本管理工具(svn软件版本管理)
- 我的世界1.8.10钻石在第几层(我的世界1.7.2钻石在哪层)
- Java开发高手必备:在电脑上轻松切换多个JDK版本
- 2022 年 Java 开发报告:Java 8 八年不到,开发者都在用什么?
- 开发java项目,选择哪个版本的JDK比较合适?
- Java版本选型终极指南:8 vs 17 vs 21特性对决!大龄程序员踩坑总结
- POI Excel导入(poi excel导入附件)
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)