java线程七之线程池

1.java常用的线程池

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();//缓存线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);//固定大小线程池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();//单线程的线程池
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);任务线程池

2.常用线程池都指向了同一个类ThreadPoolExecutor

看看上述常用线程池的源码:

缓存线程池生成源码:

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

固定大小线程池生成源码:

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

单线程的线程池生成源码:

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

任务线程池生成源码:

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
          new DelayedWorkQueue());
}
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}

从上述我们发现:其实这些常用的线程池最终使用的都是ThreadPoolExecutor这个线程池的类,那么我们重点了解下ThreadPoolExecutor这个类

3.ThreadPoolExecutor类

我们先看下这个类的构造函数:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          RejectedExecutionHandler handler) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), handler);
}
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

这四个构造函数,最终都指向了最后一个构造函数:

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {}

下面分析一下里面的参数:

corePoolSize:核心池的线程数量。正常情况下,创建的线程池没有任何线程(调用prestartCoreThread()和prestartAllCoreThreads()除外,这两个方法是表示在线程池中预创建corePoolSize个线程)。正常情况下,创建了线程池后,每到达一个任务,就会创建一个线程去执行任务,当线程池中的线程数量达到corePoolSize后,就会把达到的任务放到缓存队列中。缓存队列是后面的一个参数,一会就介绍。

maximumPoolSize:线程池的最大线程数。表示最多能创建多少个线程

keepAliveTime:正常情况下,线程池中的线程数大于corePoolSize时,并且存在没有任务执行的线程,当这些线程保持keepAliveTime这个参数的时间时,线程就会被终止并释放,当然终止和释放到corePoolSize数量为止。但是非正常情况下,调用allowCoreThreadTimeOut(boolean)时,线程池中的长时间未执行的线程数量就会被终止和释放到0为止。

unit:参数keepAliveTime的取值单位。

TimeUnit.DAYS; //天
TimeUnit.HOURS; //小时
TimeUnit.MINUTES; //分钟
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //纳秒

workQueue:这个就是corePoolSize参数中提到的缓存队列,一般使用LinkedBlockingQueue或SynchronousQueue。

threadFactory:线程工厂,主要用来创建线程。

handler:拒绝处理任务时的策略。

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

4.ThreadPoolExecutor类的继承关系

ThreadPoolExecutor继承了AbstractExecutorService,AbstractExecutorService实现了ExecutorService,ExecutorService继承了Executor。

其中经常用到的方法如下:

execute():向线程池提交一个任务,由线程池去执行

submit():向线程池提交一个任务,它与execute()的不同之处在于,它能返回Future的执行结果,具体应用可以看后面的例子

shutdown()和shutdownNow():关闭线程池

5.常用线程池的作用与示例:注意下面的示例有的没有调用shutdown()关掉线程池。

  • newCachedThreadPool

缓存线程池:它的线程池数量默认达到Integer.MAX_VALUE,可以放大量的线程。但是就是因为可以放大量的线程,所以要在程序中控制线程的数量,否则,线程量太大,很容易造成系统的瘫痪。

/**
 * Created by 
 * Date : 2018/7/19 14:12
 */
public class Main {

    public static void main(String[] args){
        new Main().test1();
    }

    public void test1(){
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for(int i=1;i<=5;i++){
            final int index=i;
            cachedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程"+index+"执行");
                }
            });
        }
    }
}

执行结果:

线程1执行
线程4执行
线程5执行
线程3执行
线程2执行

  • newFixedThreadPool

固定大小线程池:固名思义,就是可以放固定的线程数量。

/**
 * Created by WangZhiXin
 * Date : 2018/7/19 14:12
 */
public class Main {

    public static void main(String[] args) {
        new Main().test2();
    }

    public void test2() {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        for (int i = 6; i <= 10; i++) {
            final int index = i;
            fixedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程" + index + "执行");
                    try{
                        TimeUnit.SECONDS.sleep(2);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            });
        }
    }
}

执行结果:

线程6执行
线程7执行
线程8执行
线程9执行
线程10执行

这个执行结果是每2秒打印三个线程的内容。也就是执行三个线程。

  • newSingleThreadExecutor

单线程线程池:只有一个线程执行任务

/**
 * Created by WangZhiXin
 * Date : 2018/7/19 14:12
 */
public class Main {

    public static void main(String[] args) {
        new Main().test3();
    }

    public void test3() {
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
        for (int i = 6; i <= 10; i++) {
            final int index = i;
            singleThreadExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("线程" + index + "执行");
                    try{
                        TimeUnit.SECONDS.sleep(1);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            });
        }
        singleThreadExecutor.shutdown();
    }
}

执行结果:

线程6执行
线程7执行
线程8执行
线程9执行
线程10执行

每隔一秒执行一次

  • newScheduledThreadPool

任务线程池:可以按固定时间执行线程。

比如下面的例子:

/**
 * Created by WangZhiXin
 * Date : 2018/7/19 14:12
 */
public class Main {

    public static void main(String[] args) {
        new Main().test4();
    }

    public void test4() {
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
        scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程执行");
            }
        }, 1, 3, TimeUnit.SECONDS);
    }
}

执行结果:

线程执行
线程执行
线程执行
线程执行
线程执行

。。。。。。

结果是1秒后每隔3秒执行一次,注意这个方法不能加shutDown()方法,否则会被直接关掉

前面都是演示execute()方法的例子,下面再演示一个submit()方法,有返回Future的执行结果的例子:

/**
 * Created by 
 * Date : 2018/7/19 14:12
 */
public class Main {

    public static void main(String[] args) {
        new Main().test5();
    }

    public void test5(){
        List<Integer> list=new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        if (!list.isEmpty()) {
            int size = list.size();
            ExecutorService pool = Executors.newFixedThreadPool(size > 2 ? 2 : size);
            final List<Exception> errorList = new ArrayList();
            List<Future> rowResult = new CopyOnWriteArrayList<Future>();
            for (int i = 0; i < size; i++) {
                final Integer index = list.get(i);
                rowResult.add(pool.submit(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            System.out.println(index);
                        } catch (Exception e) {
                            //添加异常信息
                            errorList.add(e);
                        }
                    }
                }));
            }
            //等待处理结果
            for (Future f : rowResult) {
                try{
                    f.get();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
            //启动一次顺序关闭,执行以前提交的任务,但不接受新任务。如果已经关闭,则调用没有其他作用
            pool.shutdown();
            if (!errorList.isEmpty()) {
                //抛出异常信息
                System.out.println("异常信息:"+errorList.get(0).getMessage());
            }
        }
    }
}

执行结果:

1
2
3
5
4

其中f.get()这个方法是阻塞等待处理结果,直到所有线程都处理完了并返回Future,f.get()才不会阻塞。

猜你喜欢

转载自blog.csdn.net/wangzx19851228/article/details/81116113