线程池 一、executor接口和ExecutorService接口介绍

工作这么多年,很少有时间写博客,昨天和一个正在跳槽找工作的同学交流,他是做web的,面试的时候被问到了线程池一块的技术,被难住了!这让我不禁也想巩固下我这方便的基础了,天天在用的东西,尤其是像我们这种做互联网服务端开发的,高并发处理中创建一个优异Thread Pool对线程进行复用还是很重要的!俗话说好记性不如烂笔头,先介绍下Executor接口吧!


为什么需要创建线程池:

(1)因为服务器如果每一个请求都会创建一个新线程,会导致性能上的瓶颈,因为线程创建和销毁都需要jvm不停的处理,如果一个线程执行的时间 < (线程创建时间+线程销毁的时间)的时候,我们就要考虑线程的复用了!

(2)、线程数量创建过多,没有有效的管理,反而起到的是副作用,会大大降低系统的性能的!

(3)、我们要根据具体的业务需求不同,结合操作系统的处理器CPU核数,能够合理的控制线程池大小!选择不同策略的线程池,盲目使用也会带来一定风险,比如内存泄漏,死锁,并发问题.....

线程池的好处:

(1)、降低资源消耗:线程复用。

(2)、提高响应速度:有任务的时候,不需要去等待创建线程,直接使用已有的线程;

(3)、管理:线程池对线程进行统一分配,调优,监控等等;


一、Executor 接口 (友情提示:不是类Executors)

线程与Executor框架线程,操作系统各自扮演的角色:任务的2级调度

 

  java.util.concurrent.Executor: 大部分线程池相关的接口都是实现这个接口的

public interface Executor {

 

    void execute(Runnable command);

}

 他的子接口和实现的类如下:

​​​

完整的Executor接口继承实现结构图如下:

我们重点看我圈出来的不分,基本就是你学习线程池这块要反复看的内容;

我们继续顺着源代码往下分析:(绿色实线箭头是继承,虚线是接口实现)

1、ExecutorService:servirce顾名思义是提供服务的接口。

【首先申明executor架构下的ForkJoinPool思想和其他的接口类不一样,ForkJoinPool的优势在于,可以充分利用多cpu,多核cpu的优势,把一个任务拆分成多个“小任务”,把多个“小任务”放到多个处理器核心上并行执行;当多个“小任务”执行完成之后,再将这些执行结果合并起来;(后续具体介绍ForkJoinPool用法)】;

(1)shutdown: 具体源码实现是:

public void shutdown() {

        final ReentrantLock mainLock = this.mainLock;

        mainLock.lock();

        try {

        //想操作shutdownshutdownnow权限check ModifyThread权限通过

            checkShutdownAccess();

       //runstate设为给定的目标

            advanceRunState(SHUTDOWN);

    //中断一些正在等待任务的的空闲的线程,

            interruptIdleWorkers();

//取消和清楚,由于shutdown策略中所有不应该继续运行的工作队列

            onShutdown(); // hook for ScheduledThreadPoolExecutor

        } finally {

            mainLock.unlock();

        }

        tryTerminate();

    }

下面我谢的一个简单的test:

总结:shutdown 调用之后,线程池拒绝接受新submit的任务,但是会继续运行在shutdown之前的任务;

(2)、shutdownNow:源码相似,他是停止正在运行的任务,返回空闲的线程,并且拒绝接受新的任务

(3)、isShutdown():当前executor是否已经shutdown

(4)、isTerminated();若关闭后所有任务都已完成,则返回true。注意除非首先调用shutdown或shutdownNow,否则isTerminated永不为true;

(6)、submit():提交新的任务,任务分Runnable和Callable类型

(7)、invokeAll()和invokeAny(),在批量执行或多选一的业务场景中非常方便。invokeAll()在所有任务都完成(包括成功/被中断/超时)后才会返回,invokeAny()在任意一个任务成功(或ExecutorService被中断/超时)后就会返回。

 

package com.executor.test;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Description:
 * User: ZhuRong
 * Date: 2018-07-20  13:18
 */
public class ShutDowmTest {
    static int index = 1;
    public static void main(String[] args) {
        try {
            //创建一个线程池,可以同一时间容乃3条线程
            ExecutorService executorService = Executors.newFixedThreadPool(3);
            for (int i = 0; i < 5; i++) {
                executorService.submit(new AutoIncressNum());
            }
            Thread.sleep(2000L);
            executorService.shutdown();
            for (int i = 0; i < 3; i++) {
                executorService.submit(new AutoIncressNum());
            }
            System.out.println(executorService.isShutdown());
            System.out.println(executorService.isTerminated());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static class AutoIncressNum implements Runnable {
        @Override
        public void run() {
            try {
                Random random = new Random();
                Thread.sleep(1000L + random.nextInt(5000));
                System.out.println(Thread.currentThread().getName()+":"+index);
                index++;
            } catch (Exception e) {
                System.out.println(Thread.currentThread().getName() + " Interrupted!");
                e.printStackTrace();
            }

        }
    }
}

package com.executor.test;

import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Description:
 * User: ZhuRong
 * Date: 2018-07-20  13:18
 */
public class ShutDownNowTest {
    static int index = 1;
    public static void main(String[] args) {
        try {
            //创建一个线程池,可以同一时间容乃3条线程
            ExecutorService executorService = Executors.newFixedThreadPool(3);
            for (int i = 0; i < 5; i++) {
                executorService.submit(new AutoIncressNum());
            }
            Thread.sleep(2000L);
            List<Runnable> list =  executorService.shutdownNow();
            System.out.println(executorService.isShutdown());
            System.out.println(executorService.isTerminated());
            for(Runnable l: list){
                System.out.println(l.toString());
            }
            for (int i = 0; i < 2; i++) {
                executorService.submit(new AutoIncressNum());
            }

        } catch (Exception e) {
//            e.printStackTrace();
        }
    }

    static class AutoIncressNum implements Runnable {
        @Override
        public void run() {
            try {
                Random random = new Random();
                Thread.sleep(1000L + random.nextInt(5000));
                System.out.println(Thread.currentThread().getName()+":"+index);
                index++;
            } catch (Exception e) {
                System.out.println(Thread.currentThread().getName() + " Interrupted!");
                e.printStackTrace();
            }

        }
    }
}

先介绍这2个接口,后面有时间继续介绍其他的线程池相关的接口和类!这个测试案例建议和大家还是跑一跑就懂了ExecutorService这一个接口的里面的api应用了!

猜你喜欢

转载自blog.csdn.net/Z0157/article/details/81135008