java并发之线程池api介绍ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor类是ScheduleExecutorService接⼝的实现类。
这个接⼝是⽤来开启延时任务的线程池。
他会将这些任务都放⼊⼀个队列,先进先出。
scheduleAtFixedRate:
只有前⼀个任务执⾏完毕之后,后⾯的任务才能接着去执⾏;如果前⼀个任务执⾏的时间超过了周期时间,等前⼀个任务执⾏完毕之后,⽴即执⾏后⾯的任务。
如果前⼀个任务执⾏的时间少于周期时间,则需要再等待周期时间减任务执⾏时间才会执⾏后⼀个任务。
案例:
public class TestMain {
static int a=0;
public static void main(String[] args){
//延迟周期任务线程池,corePoolSize表⽰线程池中的线程数量,这个数量包括空闲数量
ScheduledThreadPoolExecutor executor=new ScheduledThreadPoolExecutor(3);
/*
将任务防⽌到延迟线程池中,这⾥表⽰⼀开始延迟4秒钟,后⾯每10秒执⾏⼀次这个线程
*/
executor.scheduleAtFixedRate(new Runnable(){
@Override
public void run(){
System.out.println("测试:"+(TestMain.a++));
try{
Thread.sleep(4000);
}catch(Exception e){
e.printStackTrace();
}
}
},4,10, TimeUnit.MILLISECONDS);
}
}
如果正常情况下,当前任务执⾏完之后需要再等待6秒之后才会执⾏下⼀个任务。java线程池创建的四种
输出结果:
测试:0
测试:1
测试:2
测试:3
。。。。。。
如果是scheduleWithFixedDelay ⽅法的话,虽然结果是⼀样的。但是当前任务执⾏完之后需要再等待10秒之后才会执⾏下⼀个任务。scheduleWithFixedDelay与scheduleAtFixedRate的区别就是⼀个在运⾏任务的时候就计时,⼀个任务运⾏完之后才计时。
任务队列
BlockingQueue
主要是⽤来存错已经提交的任务,但是该任务没未能马上分配到线程去执⾏的任务,该api是⼀个接⼝。
常⽤的实现类有:
1、LinkedBlockingQueue
该api理论上是⽆界限,除⾮系统资源耗尽,否则可以⼀直讲任务存⼊该队列中。
采⽤先进先出策略。
2、ArrayBlockingQueue
有界限的任务队列,必须传⼊⼀个代表该队列最⼤容量的参数。
采⽤先进先出策略。
3、SynchronousQueue
直接提交的队列,提交的任务将会被直接分配线程执⾏。如果线程数达到最⼤数量,则会执⾏拒绝策略。4、PriorityBlockingQueue
可指定任务的优先顺序,优先级越⾼其任务越优先分配到线程去执⾏。
使⽤Executors提供的五⼤线程池创建线程池newSingleThreadExecutor
创建⼀个只有⼀个线程的线程池,其任务队列使⽤的是LinkedBlockingQueue⽆界限队列。
因为这⾥的队列是采⽤的FIFO算法,⽽且线程池的线程数量⼜只有⼀个,因此这⾥的请求是有顺序的。
任务是按添加的顺序执⾏的,但是他不能保证每个线程执⾏的结果是有序的。
//创建单个线程的线程池
/* ExecutorService executor= wSingleThreadExecutor();
for(int a=0;a<10;a++){
PrintTask task=new PrintTask(a);
}
executor.shutdown();
*/
newCachedThreadPool
⼀开始没有固定的线程数,当有任务直接创建⼀个线程,如果有空闲的线程直接使⽤,若没有则继续创建。
//创建⼀个⽆界限的线程池
/* ExecutorService wCachedThreadPool();
for(int a=0;a<100;a++){
PrintTask task=new PrintTask(a);
}
executorService.shutdown();*/
newFixedThreadPool
创建⼀个固定数量的线程池,其任务队列使⽤的是LinkedBlockingQueue⽆界限队列。
//固定数量的线程池
/* ExecutorService wFixedThreadPool(10);
for(int a=0;a<20;a++){
PrintTask task=new PrintTask(a);
//当任务超过线程池的线程池数量之后,会把任务放⼊线程池的任务队列种。
}*/
newScheduledThreadPool
ExecutorService executorService = wScheduledThreadPool(30);
for (int a = 0; a < 10; a++) {
PrintTask task = new PrintTask(a);
}
executorService.shutdown();
PrintTask类:
public class PrintTask implements Runnable {
private int a;
public PrintTask(int a) {
this.a = a;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "----" + a);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程结束----" + a);
}
}
newWorkStealingPool
该线程池和其他四个都不同,他创建线程池传递的参数是parallelism ,表⽰并发数量,创建的任务队列的个数是 parallelism+1 个,线程也是paralleism+1个,当各⾃的线程维护的队列的任务完成之后,就会从其他的线程队⾥偷取任务来执⾏。
这也是newWorkStealingPool和以上四种线程数很⼤不同的区别,⽽且其他四种线程只维护⼀个任务队列。
ExecutorService
ExecutorService注重于线程池的管理。
submit():
提交⼀个可运⾏的任务到线程池中,并返回⼀个该任务的Future(任务执⾏结果的⼀个包装对象),Future提供的get⽅法,将在成功完成后返回给定的结果,get ()⽅法可以配置等待时间。
Future对象也可以取消这个任务的执⾏。
execute():
将该任务添加到线程池中,在某个时间执⾏。和submit不同的是,execute⽅法没有返回值。
shutdown():
⽅法允许先前提交的任务在线程池终⽌之前执⾏,但不会接受新的任务了,若任务全部执⾏完毕,线
程池终⽌。
这个⽅法会先让线程池的状态预设置成停⽌,但只有在调⽤该⽅法之前的任务执⾏完之后才会停⽌掉线程池。
shutdownNow():
阻⽌任务队列中任务的启动并且尝试停⽌正在执⾏的任务,⼀旦终⽌,线程池中将没有任务执⾏,并且不能提交新的任务。
说笼统些,就是⽴马停⽌线程池,对于正在执⾏的任务会尝试去中断,它是通过interrupt()⽅法去中断任务的,对于⼀些没有sleep,wait,Condition的任务来说是没有办法中断的,只能等待执⾏完毕之后才停⽌线程池。
isisTerminated():
只有当线程池关闭了,该⽅法才会返回true。
例如:
public class TestExecutors{
public static void main(String[] args) throws InterruptedException{
ExecutorService executorService = new ThreadPoolExecutor(1, 3, 5,
TimeUnit.SECONDS, new LinkedBlockingDeque<>(4), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardOldestPolicy());
System.out.println("inited");
for (int i = 0; i < 20; i++){
int finalI = i;
try{
TimeUnit.SECONDS.sleep(10);
System.out.println(finalI);
System.out.println(Thread.currentThread().getName());
}catch (InterruptedException e){
e.printStackTrace();
}
});
}
System.out.println(executorService.isTerminated());
executorService.shutdown();
System.out.println(executorService.isTerminated());
System.out.println(1111111);
}
}
结果:
从结果上看到,调⽤了shutdown() ⽅法,并不是真正的将线程池关闭了。但如果换成shutdownNow()就会直接关闭线程池了。
CompletionService
该接⼝和ExecutorService⼗分类似,不过CompletionService更注重的是任务队列的执⾏情况,实际上CompletionService是Executor 和BlockQueue的结合。
事实上CompletionService就是⽤来管理线程管理线程池提交的那些任务完成后的结果的⼀个api。
task():
等待当前执⾏的任务的完成情况,返回Future对象。
任务的创建有两种创建⽅式:Runnale,Callable
1、Runnable:这种⽅式⼀般是⽤来执⾏⽆返回值的。
2、Callable:这种任务的创建⽅式可以返回执⾏结果。
可以看成⼀个线程就是⼀个任务,然后让Executors⼯⼚提供⼀个线程池去管理这些任务。ExecutorService主要
Executors是操作线程池的⼯具类,Executor是所有线程池的终极⽗接⼝,ExecutorService⽐较注重任务的运⾏和管理。
ForkJoinTask:可以将⼀个任务分解成多个,然后执⾏完之后再将任务的结果合并。
ForkJoinTask它的实现类有RecursiveTask。
注意:
线程池技术,内部使⽤了⼀个任务队列的⽅式。当任务超出了最⼤线程数量之后,则会将任务阻塞在任务队列中,然后等待现在正在执⾏任务的线程,执⾏完当前任务之后,才会去从任务队列中取任务执⾏,知道所有任务执⾏完毕。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论