Java线程池

什么是线程池

线程池是指在初始化一个多线程应用程序过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是新建一个线程。线程池中线程的数量通常完全取决于可用内存数量和应用程序的需求。然而,增加可用线程数量是可能的。线程池中的每个线程都有被分配一个任务,一旦任务已经完成了,线程回到池子中并等待下一次分配任务。


java.util.concurrent.Executors提供了一个 java.util.concurrent.Executor接口的实现用于创建线程池,一个线程池包括以下四个基本组成部分:

        1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
        2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
        3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
       4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。


为什么需要线程池?

1、重用存在的线程,减少对象创建、消亡的系统开销,过于频繁的创建/销毁线程,会很大程度上影响处理效率

记创建线程消耗时间T1,执行任务消耗时间T2,销毁线程消耗时间T3

如果T1+T3>T2,那么是不是说开启一个线程来执行这个任务太不划算了!

正好,线程池缓存线程,可用已有的闲置线程来执行新任务,避免了T1+T3带来的系统开销

2、可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞

我们知道线程能共享系统资源,如果同时执行的线程过多,就有可能导致系统资源不足而产生阻塞的情况


运用线程池能有效的控制线程最大并发数,避免以上的问题

3、对线程进行一些简单的管理

提供定时执行、定期执行、单线程、并发数控制等功能


线程池几个重要的类/接口


Executor
严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具
ExecutorService
真正的线程池接口。
ScheduledExecutorService
能和Timer/TimerTask类似,解决那些需要任务重复执行的问题。
ThreadPoolExecutor
ExecutorService的默认实现。
ScheduledThreadPoolExecutor
周期性任务调度的类实现
Executors
Executor的工厂类

ThreadPoolExecutor线程构造器详解
//五个参数的构造函数
public ThreadPoolExecutor(
                          int  corePoolSize,        
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,                          BlockingQueue<Runnable> workQueue
)

//六个参数的构造函数-1
public ThreadPoolExecutor(
                          int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory
)

//六个参数的构造函数-2
public ThreadPoolExecutor(
                          int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
BlockingQueue<Runnable> workQueue,
                          RejectedExecutionHandler handler
)

//七个参数的构造函数
public ThreadPoolExecutor(
                          int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler
)

int corePoolSize => 该线程池中核心线程数最大值
int maximumPoolSize => 该线程池中线程总数最大值
long keepAliveTime => 线程池中非核心线程闲置超时时长
TimeUnit unit => 参数的时间单位,枚举类型
NANOSECONDS : 1微毫秒 = 1微秒 / 1000
MICROSECONDS : 1微秒 = 1毫秒 / 1000
MILLISECONDS : 1毫秒 = 1秒 /1000
SECONDS : 秒
MINUTES : 分
HOURS : 小时
DAYS : 天
BlockingQueue<Runnable> workQueue  => 该线程池中的任务队列
维护着等待执行的Runnable对象

此队列仅保持由 execute方法提交的 Runnable任务

当所有的核心线程都在干活时,新添加的任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行任务

常用的workQueue类型:
SynchronousQueue:非阻塞队列(直接提交)
LinkedBlockingQueue:阻塞的无界(可选有界)队列
ArrayBlockingQueue阻塞的有界优先级队列
DelayQueue:时间的调度队列
ThreadFactory threadFactory  => 执行程序创建新线程时使用的工厂
例如:
new ThreadFactory() {
    public Thread new Thread(Runnable r) {
        return new Thread(r,"这是一个线程" );
    }
}
RejectedExecutionHandler handler   => 由于超出线程范围队列容量使执行被阻塞时所使用的处理程序
线程池执行任务流程


1、当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。
2、当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行
3、当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务
4、当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理

5、当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程
6、当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭

4种常用的线程池
1、newSingleThreadExecutor
生成  ==》 ExecutorService service = Executors.newSingleThreadExecutor();
源码:
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
核心线程数 和 线程总数 为1
keepAliveTime 为0,
任务队列 为 LinkedBlockingQueue

含义: 创建只有一个线程的线程池,且线程的存活时间是无限的;当该线程正繁忙时,对于新任务会进入阻塞队列中(无界的阻塞队列)
适用:一个任务一个任务执行的场景
2、newFixedThreadPool (newFixedThreadPool (int nThreads))
生成  ==》ExecutorService service = Executors.newFixedThreadPool(5);
源码:    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
核心线程数 和 线程总数 相同
keepAliveTime 为0,
任务队列 为 LinkedBlockingQueue

含义: 创建可容纳固定数量线程的池子,每隔线程的存活时间是无限的,当池子满了就不在添加线程了;如果池中的所有线程均在繁忙状态,对于新任务会进入阻塞队列中(无界的阻塞队列)
适用:执行长期的任务,性能好很多
3、newCachedThreadPool ( newFixedThreadPool (int nThreads))
生成  ==》ExecutorService service = Executors.newCachedThreadPool();
源码:
    public static ExecutorService newCachedThreadPool() {
            return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
核心线程数 0
线程总数 无限大
keepAliveTime 为60s,
任务队列 为 SynchronousQueue

含义: 当有新任务到来,则插入到SynchronousQueue中,由于SynchronousQueue是同步队列,因此会在池中寻找可用线程来执行,若有可以线程则执行,若没有可用线程则创建一个线程来执行该任务;若池中线程空闲时间超过指定大小,则该线程会被销毁。
适用:执行很多短期异步的小程序或者负载较轻的服务器
4、 ScheduledThreadPoolExecutor ( newScheduledThreadPool(int corePoolSize) )
生成  ==》ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
源码:
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
线程总数 无限大
keepAliveTime 无限大
任务队列 为 DelayedWorkQueue

含义: 创建一个固定大小的线程池,线程池内线程存活时间无限制,线程池可以支持定时及周期性任务执行,如果所有线程均处于繁忙状态,对于新任务会进入DelayedWorkQueue队列中,这是一种按照超时时间排序的队列结构
适用:周期性执行任务的场景

ExecutorService的方法

void execute()执行Runnable任务
<T> Future<T> submit(Callable<T> task)
执行Callable任务

提交一个返回值的任务用于执行,返回一个表示任务的未决结果的
Future。该 Future 的 get 方法在成功完成时将会返回该任务的结果。
<T> Future<T> submit(Runnable task, T result)
提交一个 Runnable 任务用于执行,并返回一个表示该任务的
 Future。该 Future 的 get 方法在成功完成时将会返回给定的结果
Future<?> submit(Runnable task)
提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。
该 Future 的 get 方法在成功 完成时将会返回 null
<T> List<Future<T>> invokeAll
(Collection<? extends Callable<T>> tasks)
执行给定的任务,当所有任务完成时,返回保持任务状态和结果的
Future 列表。返回列表的所有元素的 Future.isDone() 为 true
<T> List<Future<T>> invokeAll
(Collection<? extends Callable<T>> tasks,
           ong timeout, TimeUnit unit)
执行给定的任务,当所有任务完成时,返回保持任务状态和结果的
Future 列表。返回列表的所有元素的 Future.isDone() 为 true。
<T> T invokeAny
(Collection<? extends Callable<T>> tasks)
执行给定的任务,如果在给定的超时期满前某个任务已成功完成
(也就是未抛出异常),则返回其结果。一旦正常或异常返回后,
则取消尚未完成的任务。
void shutdown()
顺次地关闭ExecutorService,停止接收新的任务,等待所有已经
提交的任务执行完毕之后,关闭ExecutorService
List<Runnable> shutdownNow()
阻止等待任务启动并试图停止当前正在执行的任务,
停止接收新的任务,返回处于等待的任务列表
boolean isShutdown()
判断线程池是否已经关闭
boolean isTerminated()
如果关闭后所有任务都已完成,则返回 true。注意,除非首先
调用 shutdown 或 shutdownNow,否则 isTerminated 永不为 true。
boolean awaitTermination
(long timeout, TimeUnit unit)
等待(阻塞)直到关闭或最长等待时间或发生中断,
timeout - 最长等待时间 ,unit - timeout 参数的时间单位 
如果此执行程序终止,则返回 true;如果终止前超时期满,则返回 false 

示例

执行Runnable任务

public class Test {

    public static void main(String[] args) {

        ExecutorService service = Executors.newCachedThreadPool();
//        ExecutorService service = Executors.newFixedThreadPool(5);
//        ExecutorService service = Executors.newSingleThreadExecutor();
        
        for(int i = 0; i < 20; i ++) {
            service.execute(new MyThread(i));
        }

        service.shutdown();
    }
}


public class MyThread implements Runnable {

    public int index;

    public MyThread (int index) {
        this.index = index;
    }

    @Override
    public void run() {
        System.out.println(TimeUtils.getDateStr() + " Thread-" + Thread.currentThread().getName() + "  " + index);
        try {
            Thread.sleep(MathConstant.INT_1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

执行Callable任务
public class Test {

        ExecutorService executorService = Executors.newCachedThreadPool();   
        List<Future<String>> resultList = new ArrayList<Future<String>>();   

        //创建10个任务并执行   
        for (int i = 0; i < 10; i++){   
            //使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中   
            Future<String> future = executorService.submit(new MyThread2(i));   
            //将任务执行结果存储到List中   
            resultList.add(future);   
        }   

        //遍历任务的结果   
        for (Future<String> fs : resultList){   
                try{   
                    while(!fs.isDone());//Future返回如果没有完成,则一直循环等待,直到Future返回完成  
                    System.out.println(fs.get());     //打印各个线程(任务)执行的结果   
                }catch(InterruptedException e){   
                    e.printStackTrace();   
                }catch(ExecutionException e){   
                    e.printStackTrace();   
                }finally{   
                    //启动一次顺序关闭,执行以前提交的任务,但不接受新任务  
                    executorService.shutdown();   
                }   
        }   
}

public class MyThread2 implements Callable<String> {

    public int index;

    public MyThread2(int index) {
        this.index = index;
    }

    @Override
    public String call() throws Exception {
        String name = Thread.currentThread().getName();
        System.out.println(TimeUtils.getDateStr() + " Thread-" + name + "  " + index);
        return name;
    }
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值