java 常用 线程池_java中的5种常见线程池

一、线程池简介

周所周知,Java创建一个新线程的成本是比较高的。因此在面临大量的多线程任务时,采用线程池几乎成了惯用的做法,线程池其实也是设计模式中享元模式思想的一种应用。

一般线程池刚启动时会新建大量的(跟传入参数有关)空闲线程,程序将一个Runnable或者Callable对象传给线程池时,线程池会调用空闲线程执行他们的run()方法或者call()方法。执行完成后并不回收该线程,而是再次返回线程池中称谓空闲线程,等待下一次任务。

二、Java线程池

Java 5以前,开发者需要手动实现线程池,从Java 5 开始,Java支持了内建线程池,提供了一个Executors类来新建线程池,它位于java.util.concurrent包下,基本上所有跟并发编程相关的都在该包下面。

Java 常用的线程池有7种,他们分别是:

(1)newCachedThreadPool :创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

(2)newFixedThreadPool:创建一个固定数目的、可重用的线程池。

(3)newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。

(4)newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

(5)newSingleThreadScheduledExcutor:创建一个单例线程池,定期或延时执行任务。

(6)newWorkStealingPool:创建持有足够线程的线程池来支持给定的并行级别,并通过使用多个队列,减少竞争,它需要穿一个并行级别的参数,如果不传,则被设定为默认的CPU数量。

(7) ForkJoinPool:支持大任务分解成小任务的线程池,这是Java8新增线程池,通常配合ForkJoinTask接口的子类RecursiveAction或RecursiveTask使用。

三、示例代码(只介绍代表性的几个)

(1)newCachedThreadPool 会根据任务来临的需要决定是否创建新的线程,也就是如果来了新任务又没有空闲线程,它就会新建一个线程,下面用代码可以理解这个事情。

package com;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class Main {

public static void main(String[] args) throws Exception {

ExecutorService m=Executors.newCachedThreadPool();

for(int i=1;i<=10;i++){

final int count=i;

m.submit(new Runnable(){

@Override

public void run() {

System.out.println("线程:"+Thread.currentThread()+"负责了"+count+"次任务");

}

});

//下面这行代码注释的话,线程池会新建10个线程,不注释的话,因为会复用老线程,不会产生10个线程

//            Thread.sleep(1);

}

}

}

注释掉Thread.sleep(1)的结果如下——产生了10个线程

线程:Thread[pool-1-thread-1,5,main]负责了1次任务

线程:Thread[pool-1-thread-2,5,main]负责了2次任务

线程:Thread[pool-1-thread-3,5,main]负责了3次任务

线程:Thread[pool-1-thread-4,5,main]负责了4次任务

线程:Thread[pool-1-thread-5,5,main]负责了5次任务

线程:Thread[pool-1-thread-6,5,main]负责了6次任务

线程:Thread[pool-1-thread-7,5,main]负责了7次任务

线程:Thread[pool-1-thread-8,5,main]负责了8次任务

线程:Thread[pool-1-thread-9,5,main]负责了9次任务

线程:Thread[pool-1-thread-10,5,main]负责了10次任务

不注释掉Thread.sleep(1)的结果如下——产生了2个线程

线程:Thread[pool-1-thread-1,5,main]负责了1次任务

线程:Thread[pool-1-thread-2,5,main]负责了2次任务

线程:Thread[pool-1-thread-2,5,main]负责了3次任务

线程:Thread[pool-1-thread-2,5,main]负责了4次任务

线程:Thread[pool-1-thread-2,5,main]负责了5次任务

线程:Thread[pool-1-thread-2,5,main]负责了6次任务

线程:Thread[pool-1-thread-2,5,main]负责了7次任务

线程:Thread[pool-1-thread-2,5,main]负责了8次任务

线程:Thread[pool-1-thread-2,5,main]负责了9次任务

线程:Thread[pool-1-thread-2,5,main]负责了10次任务

(2)newFixedThreadPool 创建一个固定大小的、可重用是线程池

package com;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class Main {

public static void main(String[] args) throws Exception {

ExecutorService m=Executors.newFixedThreadPool(4);

for(int i=1;i<=10;i++){

final int count=i;

m.submit(new Runnable(){

@Override

public void run() {

System.out.println("线程:"+Thread.currentThread()+"负责了"+count+"次任务");

}

});

Thread.sleep(1000);

}

}

}

结果如下:

线程:Thread[pool-1-thread-1,5,main]负责了1次任务

线程:Thread[pool-1-thread-2,5,main]负责了2次任务

线程:Thread[pool-1-thread-3,5,main]负责了3次任务

线程:Thread[pool-1-thread-4,5,main]负责了4次任务

线程:Thread[pool-1-thread-1,5,main]负责了5次任务

线程:Thread[pool-1-thread-2,5,main]负责了6次任务

线程:Thread[pool-1-thread-3,5,main]负责了7次任务

线程:Thread[pool-1-thread-4,5,main]负责了8次任务

线程:Thread[pool-1-thread-1,5,main]负责了9次任务

线程:Thread[pool-1-thread-2,5,main]负责了10次任务

(3)newScheduledThreadPool创建一个定长线程池,支持定时及周期性任务执行。

package com;

import java.util.Date;

import java.util.concurrent.Executors;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.TimeUnit;

public class Main {

public static void main(String[] args) throws Exception {

// 指定大小为4

ScheduledExecutorService m = Executors.newScheduledThreadPool(4);

m.scheduleAtFixedRate(new Runnable() {

@Override

public void run() {

Date now = new Date();

System.out.println("线程" + Thread.currentThread() + "报时:" + now);

}

}, 1, 1, TimeUnit.SECONDS); // 延迟1s秒执行,每隔1s执行一次

}

}

结果

线程Thread[pool-1-thread-1,5,main]报时:Thu Sep 10 14:55:15 CST 2015

线程Thread[pool-1-thread-1,5,main]报时:Thu Sep 10 14:55:16 CST 2015

线程Thread[pool-1-thread-2,5,main]报时:Thu Sep 10 14:55:17 CST 2015

线程Thread[pool-1-thread-1,5,main]报时:Thu Sep 10 14:55:18 CST 2015

线程Thread[pool-1-thread-1,5,main]报时:Thu Sep 10 14:55:19 CST 2015

线程Thread[pool-1-thread-2,5,main]报时:Thu Sep 10 14:55:20 CST 2015

线程Thread[pool-1-thread-2,5,main]报时:Thu Sep 10 14:55:21 CST 2015

线程Thread[pool-1-thread-2,5,main]报时:Thu Sep 10 14:55:22 CST 2015

线程Thread[pool-1-thread-2,5,main]报时:Thu Sep 10 14:55:23 CST 2015

线程Thread[pool-1-thread-2,5,main]报时:Thu Sep 10 14:55:24 CST 2015

线程Thread[pool-1-thread-2,5,main]报时:Thu Sep 10 14:55:25 CST 2015

线程Thread[pool-1-thread-2,5,main]报时:Thu Sep 10 14:55:26 CST 2015

线程Thread[pool-1-thread-2,5,main]报时:Thu Sep 10 14:55:27 CST 2015

线程Thread[pool-1-thread-2,5,main]报时:Thu Sep 10 14:55:28 CST 2015

线程Thread[pool-1-thread-2,5,main]报时:Thu Sep 10 14:55:29 CST 2015

线程Thread[pool-1-thread-2,5,main]报时:Thu Sep 10 14:55:30 CST 2015

(4)newWorkStealingPool创建一个带并行级别的线程池,并行级别决定了同一时刻最多有多少个线程在执行,如不穿如并行级别参数,将默认为当前系统的CPU个数。下面用代码来体现这种并行的限制,从结果中可以看到,同一时刻只有两个线程执行。

package com;

import java.util.Date;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class Main {

public static void main(String[] args) throws Exception {

// 设置并行级别为2,即默认每时每刻只有2个线程同时执行

ExecutorService m = Executors.newWorkStealingPool(2);

for (int i = 1; i <= 10; i++) {

final int count=i;

m.submit(new Runnable() {

@Override

public void run() {

Date now=new Date();

System.out.println("线程" + Thread.currentThread() + "完成任务:"

+ count+"   时间为:"+    now.getSeconds());

try {

Thread.sleep(1000);//此任务耗时1s

} catch (InterruptedException e) {

e.printStackTrace();

}

}

});

}

while(true){

//主线程陷入死循环,来观察结果,否则是看不到结果的

}

}

}

结果:

线程Thread[ForkJoinPool-1-worker-1,5,main]完成任务:1   时间为:7

线程Thread[ForkJoinPool-1-worker-0,5,main]完成任务:2   时间为:7

线程Thread[ForkJoinPool-1-worker-1,5,main]完成任务:3   时间为:8

线程Thread[ForkJoinPool-1-worker-0,5,main]完成任务:4   时间为:8

线程Thread[ForkJoinPool-1-worker-1,5,main]完成任务:5   时间为:9

线程Thread[ForkJoinPool-1-worker-0,5,main]完成任务:6   时间为:9

线程Thread[ForkJoinPool-1-worker-1,5,main]完成任务:7   时间为:10

线程Thread[ForkJoinPool-1-worker-0,5,main]完成任务:8   时间为:10

线程Thread[ForkJoinPool-1-worker-1,5,main]完成任务:9   时间为:11

线程Thread[ForkJoinPool-1-worker-0,5,main]完成任务:10   时间为:11

三、总结

以上几个线程池基本满足了常用的线程池需求,开发者可根据场景灵活选中,其中可以实现大任务分解的ForkJoinPool线程池的介绍因为篇幅较长,专门单独写了一篇博客,地址是: Java 多线程中的任务分解机制-ForkJoinPool详解

---------------------

作者:山中小僧

来源:CSDN

原文:https://blog.csdn.net/a369414641/article/details/48342253

版权声明:本文为博主原创文章,转载请附上博文链接!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值