多线程编程(六)-Executor与ThreadPoolExecutor的使用
- 使用Executors工厂类创建线程池
1、使用newCachedThreadPool()方法创建无界线程池
newCachedThreadPool()方法创建的是无界线程池,可以进行线程自动回收,此类线程池中存放线程个数理论值为Integer.MAX_VALUE最大值。
package com.wjg.unit4_2_2; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class Run {
public static void main(String[] args) throws InterruptedException {
Run run = new Run();
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
executorService.execute(run.new MyRunnable(" "+(i+1)));
}
Thread.sleep(3000);
System.out.println();
System.out.println();
for (int i = 0; i < 5; i++) {
executorService.execute(run.new MyRunnable(" "+(i+1)));
}
} public class MyRunnable implements Runnable{
private String username; public MyRunnable(String username) {
this.username = username;
} @Override
public void run() {
System.out.println(Thread.currentThread().getName()+" username="+username+" begin "+System.currentTimeMillis());
System.out.println(Thread.currentThread().getName()+" username="+username+" end "+System.currentTimeMillis());
} }
}
执行结果:
pool-1-thread-1 username= 1 begin 1488268086641
pool-1-thread-3 username= 3 begin 1488268086641
pool-1-thread-2 username= 2 begin 1488268086641
pool-1-thread-2 username= 2 end 1488268086641
pool-1-thread-4 username= 4 begin 1488268086642
pool-1-thread-4 username= 4 end 1488268086642
pool-1-thread-3 username= 3 end 1488268086641
pool-1-thread-1 username= 1 end 1488268086641
pool-1-thread-5 username= 5 begin 1488268086642
pool-1-thread-5 username= 5 end 1488268086642
pool-1-thread-5 username= 1 begin 1488268089647
pool-1-thread-3 username= 3 begin 1488268089648
pool-1-thread-4 username= 4 begin 1488268089648
pool-1-thread-1 username= 2 begin 1488268089647
pool-1-thread-1 username= 2 end 1488268089648
pool-1-thread-4 username= 4 end 1488268089648
pool-1-thread-3 username= 3 end 1488268089648
pool-1-thread-2 username= 5 begin 1488268089648
pool-1-thread-2 username= 5 end 1488268089648
pool-1-thread-5 username= 1 end 1488268089648
通过线程的名字,可以看出来线程是从池中取出来的,是可以复用的。
2、使用newCachedThreadPool(ThreadFactory)定制线程工厂
构造函数ThreadFactory是实现定制Thread的作用,具体可以看下面的例子。
package com.wjg.unit4_2_3; import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory; public class Run {
public static void main(String[] args) {
Run run = new Run();
MyThreadFactory factory = run.new MyThreadFactory();
ExecutorService executorService = Executors.newCachedThreadPool(factory);
executorService.execute(new Runnable() { @Override
public void run() {
System.out.println("当前线程的自定义名称为:"+ Thread.currentThread().getName());
}
});
} public class MyThreadFactory implements ThreadFactory{ @Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("自定义名称:"+new Date());
return thread;
} }
}
执行结果:
当前线程的自定义名称为:自定义名称:Tue Feb 28 15:58:13 CST 2017
3、使用newFixedThreadPool(int) 方法创建有界线程池
此方法创建的是有界线程池,也就是池中的线程的个数可以指定最大值。
package com.wjg.unit4_2_4; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class Run {
public static void main(String[] args) {
Run run = new Run();
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 5; i++) {
executorService.execute(run.new MyRunnable(" "+(i+1)));
}
} public class MyRunnable implements Runnable{
private String username; public MyRunnable(String username) {
this.username = username;
} @Override
public void run() {
System.out.println(Thread.currentThread().getName()+" username="+username+" begin "+System.currentTimeMillis());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" username="+username+" end "+System.currentTimeMillis());
} }
}
执行结果:
pool-1-thread-1 username= 1 begin 1488269132995
pool-1-thread-3 username= 3 begin 1488269132995
pool-1-thread-2 username= 2 begin 1488269132995
pool-1-thread-2 username= 2 end 1488269136000
pool-1-thread-3 username= 3 end 1488269136000
pool-1-thread-2 username= 4 begin 1488269136000
pool-1-thread-3 username= 5 begin 1488269136000
pool-1-thread-1 username= 1 end 1488269136000
pool-1-thread-2 username= 4 end 1488269139002
pool-1-thread-3 username= 5 end 1488269139002
通过执行结果可以看出,线程池中的线程最大数量为3。
4、使用newSingleThreadExecutor()方法创建单一线程池
此方法可以创建单一线程池,线程池里只有一个线程,单一线程池可以实现以队列的方式来执行任务。
package com.wjg.unit4_2_5; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class Run {
public static void main(String[] args) {
Run run = new Run();
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
executorService.execute(run.new MyRunnable(" "+(i+1)));
}
} public class MyRunnable implements Runnable{
private String username; public MyRunnable(String username) {
this.username = username;
} @Override
public void run() {
System.out.println(Thread.currentThread().getName()+" username="+username+" begin "+System.currentTimeMillis());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" username="+username+" end "+System.currentTimeMillis());
} }
}
执行结果:
pool-1-thread-1 username= 1 begin 1488269392403
pool-1-thread-1 username= 1 end 1488269395409
pool-1-thread-1 username= 2 begin 1488269395409
pool-1-thread-1 username= 2 end 1488269398412
pool-1-thread-1 username= 3 begin 1488269398413
pool-1-thread-1 username= 3 end 1488269401418
pool-1-thread-1 username= 4 begin 1488269401418
pool-1-thread-1 username= 4 end 1488269404422
pool-1-thread-1 username= 5 begin 1488269404422
pool-1-thread-1 username= 5 end 1488269407423
由执行结果的线程名字可以看出,线程池中只有一个线程。
- ThreadPoolExecutor的使用
类ThreadPoolExecutor可以非常方便的创建线程池对象。
常用的构造方法有ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue)
参数解释如下:
corePoolSize:池中所保存的线程数,包括空闲线程数,也就是核心池的大小。
maximumPoolSize:池中允许的最大线程数
keepAliveTime:当线程数量大于corePoolSize值时,在没有超过指定的时间内是不从线程池中将空闲线程删除的,如果超过此时间,则删除。
unit:keepAliveTime参数的时间单位。
workQueue:执行前用于保持任务的队列。此队列仅保存由execute方法提交的Runnable任务。
为了更好地理解这些参数在使用上的一些关系,可以将它们进行详细化的注释:
(1)A代表execute(runnable)欲执行的runnable的数量;
(2)B代表corePoolSize;
(3)C代表maximumPoolSize;
(4)D代表A-B(假设A>=B);
(5)E代表newLinkedBlockingDeque<Runnable>()队列,无构造函数。
(6)F代表SynchronousQueue队列;
(7)G代表keepAliveTime;
在使用线程池的过程下,会出现以下的集中情况:
(1)如果A<=B,那么马上创建线程运行这个任务,并不放入扩展队列Queue中,其他参数功能忽略;
(2)如果A>B&&A<=C&&E,则C和G参数忽略,并把D放入E中等待被执行;
(3)如果A>B&&A<=C&&F,则C和G参数有效,并且马上创建线程运行这些任务,而不把D放入F中,D执行完任务后在指定时间后发生超时时将D进行清除。
(4)如果A>B&&A>C&&E,则C和G参数忽略,并把D放入E中等待被执行;
(5)如果A>B&&A>C&&F,则处理C的任务,其他任务则不再处理抛出异常;
方法getActiveCount()的作用是取得有多少个线程正在执行任务。
方法getPoolSize()的作用是获得当前线程池里面有多少个线程,这些线程数包括正在执行任务的线程,也包括正在休眠的线程。
方法getCompletedTaskCount()的作用是取得有多少个线程已经执行完任务了。
方法getCorePoolSize()的作用是取得构造方法传入的corePoolSize参数值。
方法getMaximumPoolSize()的作用是取得构造方法传入的maximumPoolSize的值。
方法getTaskCount()的作用是取得有多少个任务发送给了线程池。
方法shutdown()的作用是使当前未执行完的线程继续执行,而不再添加新的任务task,该方法不会阻塞,调用之后,主线程main马上结束,而线程池会继续运行直到所有任务执行完才会停止。
方法shutdownNow()的作用是中断所有的任务task,并且抛出InterruptedException异常,前提是在Runnable中使用if(Thread.currentThread().isInterrupted()==true)语句来判断当前线程的中断状态,而未执行的线程不再执行,也就是从执行队列中清除。如果不手工加if语句及抛出异常,则池中正在运行的线程知道执行完毕,而未执行的线程不再执行,也从执行队列中清除。
方法isShutDown()的作用是判断线程池是否已经关闭。
方法isTerminating()的作用是判断线程池是否正在关闭中。
方法isTerminated()的作用是判断线程池是否已经关闭。
方法awaitTermination(long timeout,TimeUnit unit)的作用是查看在指定的时间之内,线程池是否已经终止工作,也就是最多等待多少时间后去判断线程池是否已经终止工作。
方法allowsCoreThreadTimeOut(boolean) 的作用是配置核心线程是否有超时的效果。
方法prestartCoreThread()的作用是每调用一次就创建一个核心线程,返回值为boolean。
方法prestartAllCoreThreads()的作用是启动全部核心线程,返回值是启动核心线程的数量。
- 线程池ThreadPoolExecutor的拒绝策略
线程池中的资源全部被占用的时候,对新添加的Task任务有不同的处理策略,在默认的情况ThreadPoolExecutor类中有4个不同的处理方式:
(1)AbortPolicy:当任务添加到线程池中被拒绝时,它将抛出RejectedExecutionException异常。
(2)CallerRunsPolicy:当任务添加到线程池被拒绝时,会使用调用线程池的Thread线程对象处理被拒绝的任务。
(3)DiscardOldestPolicy:当任务添加到线程池被拒绝时,线程池会放弃等待队列中最旧的未处理任务,然后将拒绝的任务添加到等待队列中。
(4)DiscardPolicy:当任务添加到线程池中被拒绝时,线程池将丢弃被拒绝的任务。
多线程编程(六)-Executor与ThreadPoolExecutor的使用的更多相关文章
- Python:使用threading模块实现多线程编程
转:http://blog.csdn.net/bravezhe/article/details/8585437 Python:使用threading模块实现多线程编程一[综述] Python这门解释性 ...
- 多线程编程学习十一(ThreadPoolExecutor 详解).
一.ThreadPoolExecutor 参数说明 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keep ...
- java核心-多线程-Java多线程编程涉及到包、类
Java有关多线程编程设计的类主要涉及两个包java.lang和java.util.concurrent两个包 java.lang包,主要是线程基础类 <1>Thread <2> ...
- Java多线程编程:Callable、Future和FutureTask浅析(多线程编程之四)
java多线程-概念&创建启动&中断&守护线程&优先级&线程状态(多线程编程之一)java多线程同步以及线程间通信详解&消费者生产者模式&死锁& ...
- Java多线程编程实战指南(核心篇)读书笔记(五)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76730459冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...
- Java多线程编程实战指南(核心篇)读书笔记(四)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76690961冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...
- Scalaz(45)- concurrency :Task-函数式多线程编程核心配件
我们在上一节讨论了scalaz Future,我们说它是一个不完善的类型,最起码没有完整的异常处理机制,只能用在构建类库之类的内部环境.如果scalaz在Future类定义中增加异常处理工具的话,用户 ...
- 多线程编程1 - NSThread
每个iOS应用程序都有个专门用来更新显示UI界面.处理用户的触摸事件的主线程,因此不能将其他太耗时的操作放在主线程中执行,不然会造成主线程堵塞(出现卡机现象),带来极坏的用户体验.一般的解决方案就是将 ...
- C++多线程编程(入门实例)
多线程在编程中有相当重要的地位,我们在实际开发时或者找工作面试时总能遇到多线程的问题,对多线程的理解程度从一个侧面反映了程序员的编程水平. 其实C++语言本身并没有提供多线程机制(当然目前C++ 11 ...
随机推荐
- 02:OC和C对比
1.源文件对比 C语言中常见源文件.h头文件,.c文件 文件扩展名 源类型 .h 头文件,用于存放函数声明 .c C语言源文件,用于实现头文件中声明的方法 OC中的源文件.h头文件,.m与.mm的实现 ...
- SVN代码管理发布
1.svn的独立模式应用 2.svn钩子的应用(例如:代码提交前的文件格式限制,大小限制,代码发布svn成功后的备份等等) 3.大型企业的代码发布流程 有一些制度流程.逻辑方案 4.业务变更管理
- ORACLE EBS常用表
http://www.cnblogs.com/quanweiru/archive/2012/09/26/2704628.html call fnd_global.APPS_INITIALIZE(131 ...
- Android-Kotlin-接口与多态的表现
上一篇博客介绍了 Android-Kotlin-抽象类与多态的表现 :, 而这一篇博客专门介绍下 接口与多态的表现 选择包名,然后右键: 选择Class类型,会有class: 选择File类型,不会 ...
- ubuntu16.04 LTS把下载源改为阿里云的源
为什么要切换下载源到国内的源上? Ubuntu的中国服务器下载速度很慢,我们可以尝试修改软件更新源,这样下载和更新软件的速度会加快很多. 一.linux系统版本: ubuntukylin-16.04- ...
- 吐嘈OpenCV的图像旋转功能 >_<7
實在出乎我的意料!OpenCV竟然連這么簡單的功能都沒有封裝!還要讓本大爺自己動手寫!強烈要求OpenCV下一個版本添加本功能! 函數功能和這個網頁一樣,只不過這個作者寫的太糟了,我把它變得簡潔了一點 ...
- docker实用命令集合
1. 访问docker中的MySQL数据库: docker exec -it test_mysql_1 mysql -u root -p 2. 用docker命令导入或导出mysql数据: 导出doc ...
- Linux 安装JavaEE环境之jdk安装笔记
1.安装jdk 先用xftp将jdk的压缩包上传到 /opt/ 2.在/usr/local/下使用命令mkdir java创建java目录 将jdk-7u79-linux-x64.gz解压缩至/usr ...
- centos7 升级GCC版本到7.3.0
废话不多说,直接上shell,还是比较简单的.就是编译时间有点长... 都是以小时计的......,我刀片机上面一台虚拟机反正是等了3个小时 #必备组件安装 yum install -y gcc gc ...
- AndroidStudio配置LitePal
配置,许多书上还有教程都忽略了将LitePal下载下来和拷贝的过程,这里写一个详细的课程 首先,前往GitHub,下载LitePal的包. 然后解压,会看到这个 进入download 自己选个版本,然 ...