首页 > 技术文章 > ExecutorService线程池简单使用

xiaofengshan 2020-04-20 22:08 原文

简介

ExecutorService是Java中对线程池定义的一个接口,它位于java.util.concurrent包中,在这个接口中定义了和后台任务执行相关的方法。

常用方法

public <T> Future<T> submit(Callable<T> task): 执行一个任务,并获取执行结果。
public void execute(Runnable command): 执行一个任务,无返回结果。

代码

 /**
         * 第一个参数corePoolSoze核心线程数,最开始的时候是有这个线程池里面是有一定的核心线程数的;
         * 核心线程数紫瑶不手动调用方法关闭,就一直存在;
         *
         * 第二个maximumPoolSize最大线程数,线程数不够了,能扩展到最大线程是多少;
         *
         * 第三个keepAliveTime生存时间,意思是这个线程有很长时间没干活了请你把它归还给操作系统(非核心线程);
         *
         * 第四个TimeUnit.SECONDS生存时间的单位到底是毫秒纳秒还是秒自己去定义;
         *
         * 第五个是任务队列,就是我们上节课讲的BlockingQueue,各种各样的BlockingQueue你都可以往里面扔,
         * 我们这用的是ArrayBlockingQueue,先进先出,最多装入10个任务;
         *
         * 第六个是线程工厂defaultThreadFactory,他返回的是一个enw DefaultThreadFactory,它要去你去实现ThreadFactory的接口,
         * 这个接口只有一个方法叫newThread,所以就是产生线程的,可以通过这种方式产生自定义的线程,默认产生的是defaultThreadFactory,
         * 而defaultThreadFactory产生线程的时候有几个特点:new出来的时候指定了group制定了线程名字,然后指定的这个线程绝对不是守护线程,
         * 设定好你线程的优先级。自己可以定义产生的到底是什么样的线程,指定线程名叫什么(为什么要指定线程名称,有什么意义,就是可以方便出错是回溯);
         *
         * 第七个叫拒绝策略,指的是线程池忙,而且任务队列满这种情况下我们就要执行各种各样的拒绝策略,jdk默认提供了四种拒绝策略,也是可以自定义的。自定义拒绝策略需要实现RejectedExecutionHandler接口
         *
         * 1: Abort:抛异常
         *
         * 2:Discard:扔掉,不抛异常
         *
         * 3:DiscardOldest:扔掉排队时间最久的
         *
         * 4:CallerRuns:调用者处理服务,一般是主线程。
         **/
        ThreadPoolExecutor executor=new ThreadPoolExecutor(2,3,1000, TimeUnit.SECONDS,new ArrayBlockingQueue(10), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());

        ExecutorServiceDemo serviceDemo=new ExecutorServiceDemo();
        //submit() 该方法可以获取返回值 异步
        Future<String> submit = executor.submit(serviceDemo::taskOne);
        try {
            //获取返回结果,阻塞
            String result = submit.get();
            System.out.println("获取线程返回结果: "+result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        executor.execute(serviceDemo::taskOne);

    }

JDK提供的线程池

SingleThreadExecutor(单个工作线程的线程池)

简介

线程池里面只有一个线程,这一个线程也是核心线程,这个一个线程的线程池可以保证我们扔进去的任务是顺序执行的。

代码
public void singleThreadExecutorDemo(){
        ExecutorService service = Executors.newSingleThreadExecutor();
        for(int i=0; i<5; i++) {
            final int j = i;
            service.execute(()->{
                try {
                    //睡眠,占用当前线程
                    TimeUnit.MILLISECONDS.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("单个工作线程的线程池的线程名: " + Thread.currentThread().getName());
            });
        }
    }

CachedThreadPool(缓存线程池)

简介

没有核心线程,最大线程数为Integer.MAX_VALUE,产生的线程若60秒没有执行任务,将回收,他的任务队列用的是SynchronousQueue(即无队列),使用默认工厂产生线程,线程数达到最大值时采取Abort,即抛出异常。

代码
public void cachedThreadPoolDemo(){
        ExecutorService service = Executors.newCachedThreadPool();
        System.out.println("开始: "+service);
        for (int i = 0; i < 18; i++) {
            service.execute(() -> {
                try {
                    TimeUnit.MILLISECONDS.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("缓存线程池的线程名: "+Thread.currentThread().getName());
            });
        }
        try {
            TimeUnit.MILLISECONDS.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //输出线程的相关信息
        System.out.println("结束: "+service);
    }

FixedThreadPool(固定线程数的线程池)

简介

线程全是核心线程,没有非核心线程。

代码
public void fixedThreadPoolDemo(){
        //服务器核心数
        final int cpuCoreNum = 4;
        ExecutorService service = Executors.newFixedThreadPool(cpuCoreNum);
        for (int i = 0; i < 8; i++) {
            service.execute(() -> {
                try {
                    TimeUnit.MILLISECONDS.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("固定线程数的线程池的线程名: "+Thread.currentThread().getName());
            });
        }
    }

ScheduledThreadPool(定时任务线程池)

简介

根据自定义参数进行周期性执行任务,自定义核心线程数,线程最大值无上线,队列使用的是延时队列。

代码
public void scheduledPoolDemo() {
        ScheduledExecutorService service = Executors.newScheduledThreadPool(3);
        //第一个参数(Delay)第一个任务执行之前需要往后面推多长时间;
        // 第二个(period)间隔多长时间;第三个参数是时间单位;
        System.out.println("开始执行任务,时间为: " + System.currentTimeMillis());
        service.scheduleAtFixedRate(() -> {
            System.out.println("线程名为: " + Thread.currentThread().getName());
            System.out.println("定时执行任务时间: " + System.currentTimeMillis());
        }, 3, 5, TimeUnit.SECONDS);
    }

Gitee地址

https://gitee.com/zhuayng/foundation-study/blob/develop/JavaBasis/JUC/src/main/java/com/yxkj/juc/c_003/ExecutorServiceDemo.java

推荐阅读