你应该知道的ThreadPoolExecutor

为什么要有线程池来,可以参考这篇Blog Java线程实现原理

首先来简单看下Java中两种启动线程的方式。

//Extends Thread
public class MyThread extends Thread {
    @Override
    public void run(){
        //TODO 
    }

    public void main(String[] args){
        new MyThread().start();
    }
}
// Implements Runnable
public class MyRunnable implements Runnable{
    @Override
    public void run(){
        //TODO
    }

    public void main(String[] args){
        new Thread(new MyRunnable()).start();
    }
}

第一种方式需要继承一个Thread类,来扩展Thread的类的功能已达到运行自身逻辑的目的,从软件设计上来看这种方式使用继承来扩展功能,不是推荐的做法;从Java语言特性上来说,单继承的规约限制了MyThread的对其他类的功能的复用。因此这种方式看似简单,但是不是推荐启动线程的方法。
第二种方式通过集成Runnable接口实现其run方法完成业务逻辑的编写,并将MyRunnable的实例传给一个Thread实例,并调用Thread实例的start方法进行线程的启动。这种做法的好处是将逻辑功能与线程本事解耦出来,业务逻辑不用受到Thread的类的限制。因此这种方式算是比较合理的方式。
但是这两种方式的一个共同特点是自己启动一个Thread来运行,结合Java线程实现原理来看,Java的线程其实是映射为Linux的一个内核线程来实现的,因而线程的个数也收到了限制,同事过多的启动线程来完成任务也会找成CPU频繁的进行上下文切换造成服务器不稳定,资源分配不合理。为了解决这个问题Java线程池应允而生。

本文只介绍ThreadPoolExecutor因此本文涉及的类的继承结构如下所示:
这里写图片描述

两个比较重要的类
Executors: 快速创建ThreadPoolExecutor的工具类
ThreadPoolExecutor: 这正的线程池实现者
废话不说,先看一个实例。

public class ThreadPoolTest{
    private static ExecutorService executorService = Executors.newFixedThreadPool(5);

    public static void main(String[] args){
        executorService.execute(new MyRunnable());
    }   
}

怎么样使用起来简单易懂。
在来看看ThreadPoolExecutor的构造方法

    /**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters.
     *
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * @param unit the time unit for the {@code keepAliveTime} argument
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * @param threadFactory the factory to use when the executor
     *        creates a new thread
     * @param handler the handler to use when execution is blocked
     *        because the thread bounds and queue capacities are reached
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue}
     *         or {@code threadFactory} or {@code handler} is null
     */
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) 

注释已经对这些参数解释的足够清晰,但是要真是使用起来,new出一个ThreadPoolExecutor实例也是比较麻烦的,好在Executors工具类提供了三个适合常见场景的工厂方法,使用起来非常方便快捷。

public static ExecutorService newFixedThreadPool(int nThreads);
public static ExecutorService newSingleThreadExecutor();
public static ExecutorService newCachedThreadPool();

猜你喜欢

转载自blog.csdn.net/zhanlovepei/article/details/71641067
今日推荐