ExecutorService详解[通俗易懂]

ExecutorService详解[通俗易懂]前言    在我们的日常开发中,难免会使用到线程,部分还会用到多线程并发问题。我们知道,线程的创建和释放,需要占用不小的内存和资源。如果每次需要使用线程时,都new一个Thread的话,难免会造成资源的浪费,而且可以无限制创建,之间相互竞争,会导致过多占用系统资源导致系统瘫痪。不利于扩展,比如如定时执行、定期执行、线程中断,所以很有必要了解下ExecutorService的使用。…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

前言

        在我们的日常开发中,难免会使用到线程,部分还会用到多线程并发问题。我们知道,线程的创建和释放,需要占用不小的内存和资源。如果每次需要使用线程时,都new 一个Thread的话,难免会造成资源的浪费,而且可以无限制创建,之间相互竞争,会导致过多占用系统资源导致系统瘫痪。不利于扩展,比如如定时执行、定期执行、线程中断,所以很有必要了解下ExecutorService的使用。

        ExecutorService是Java提供的线程池,也就是说,每次我们需要使用线程的时候,可以通过ExecutorService获得线程。它可以有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞,同时提供定时执行、定期执行、单线程、并发数控制等功能,也不用使用TimerTask了。

1.ExecutorService的创建方式

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

所有线程池最终都是通过这个方法来创建的。

corePoolSize : 核心线程数,一旦创建将不会再释放。如果创建的线程数还没有达到指定的核心线程数量,将会继续创建新的核心线程,直到达到最大核心线程数后,核心线程数将不在增加;如果没有空闲的核心线程,同时又未达到最大线程数,则将继续创建非核心线程;如果核心线程数等于最大线程数,则当核心线程都处于激活状态时,任务将被挂起,等待空闲线程来执行。

maximumPoolSize : 最大线程数,允许创建的最大线程数量。如果最大线程数等于核心线程数,则无法创建非核心线程;如果非核心线程处于空闲时,超过设置的空闲时间,则将被回收,释放占用的资源。

keepAliveTime : 也就是当线程空闲时,所允许保存的最大时间,超过这个时间,线程将被释放销毁,但只针对于非核心线程。

unit : 时间单位,TimeUnit.SECONDS等。

workQueue : 任务队列,存储暂时无法执行的任务,等待空闲线程来执行任务。

threadFactory :  线程工程,用于创建线程。

handler : 当线程边界和队列容量已经达到最大时,用于处理阻塞时的程序

2.线程池的类型

2.1 可缓存线程池

ExecutorService cachePool = Executors.newCachedThreadPool();

   看看它的具体创建方式:

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

    通过它的创建方式可以知道,创建的都是非核心线程,而且最大线程数为Interge的最大值,空闲线程存活时间是1分钟。如果有大量耗时的任务,则不适该创建方式。它只适用于生命周期短的任务。

2.2 单线程池

ExecutorService singlePool = Executors.newSingleThreadExecutor();

顾名思义,也就是创建一个核心线程:

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

只用一个线程来执行任务,保证任务按FIFO顺序一个个执行。

2.3 固定线程数线程池

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

也就是创建固定数量的可复用的线程数,来执行任务。当线程数达到最大核心线程数,则加入队列等待有空闲线程时再执行。

2.4 固定线程数,支持定时和周期性任务

ExecutorService scheduledPool = Executors.newScheduledThreadPool(5);
public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue());
}

可用于替代handler.postDelay和Timer定时器等延时和周期性任务。

public ScheduledFuture<?> schedule(Runnable command,
                                       long delay, TimeUnit unit);
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit);
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                     long initialDelay,
                                                     long delay,
                                                     TimeUnit unit);

scheduleAtFixedRate和sheduleWithFixedDelay有什么不同呢?

scheduleAtFixedRate:创建并执行一个在给定初始延迟后的定期操作,也就是将在 initialDelay 后开始执行,然后在initialDelay+period 后下一个任务执行,接着在 initialDelay + 2 * period 后执行,依此类推 ,也就是只在第一次任务执行时有延时。

sheduleWithFixedDelay:创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟,即总时间是(initialDelay +  period)*n

2.4 手动创建线程池

private ExecutorService pool = new ThreadPoolExecutor(3, 10,
            10L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>(512), Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy());

可以根据自己的需求创建指定的核心线程数和总线程数。

3. 如何终止一个周期性任务呢?

直接上源码你就懂了:

public final class LgExecutorService {

    private ConcurrentHashMap<String, Future> futureMap = new ConcurrentHashMap<>();

    private ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(5);


    private LgExecutorService() {

    }

    private static final class InnerExecutorService {
        private static final LgExecutorService INSTANCE = new LgExecutorService();
    }

    public static LgExecutorService getInstance() {
        return InnerExecutorService.INSTANCE;
    }

    public ConcurrentHashMap<String, Future> getFutureMap() {
        return futureMap;
    }

    public void execute(Runnable runnable) {
        if (runnable != null) {
            executorService.execute(runnable);
        }
    }

    /**
     * @param runnable
     * @param delay    延迟时间
     * @param timeUnit 时间单位
     */
    public void sheduler(Runnable runnable, long delay, TimeUnit timeUnit) {
        if (runnable != null) {
            executorService.schedule(runnable, delay, timeUnit);
        }
    }

    /**
     * 执行延时周期性任务
     *
     * @param runnable {@code LgExecutorSercice.JobRunnable}
     * @param initialDelay 延迟时间
     * @param period       周期时间
     * @param timeUnit     时间单位
     */
    public <T extends JobRunnable> void sheduler(T runnable, long initialDelay, long period, TimeUnit timeUnit) {
        if (runnable != null) {
            Future future = executorService.scheduleAtFixedRate(runnable, initialDelay, period, timeUnit);
            futureMap.put(runnable.getJobId(), future);
        }
    }

    public static abstract class JobRunnable implements Runnable {

        private String jobId;

        public JobRunnable(@NonNull String jobId) {
            this.jobId = jobId;
        }

        /**
         * 强制终止定时线程
         */
        public void terminal() {
            try {
                Future future = LgExecutorService.getInstance().getFutureMap().remove(jobId);
                future.cancel(true);
            } finally {
                System.out.println("jobId " + jobId + " had cancel");
            }
        }

        public String getJobId() {
            return jobId;
        }

    }
    
}

自己写个demo测试后就知道结果了,还是自己动下手吧。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/195018.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • drop in session_drop constraint

    drop in session_drop constraint//aspx’>//aspx.csprotectedvoidPage_Load(objectsender,EventArgse){if(!IsPostBack){SqlConnectioncn=newSqlConnection(@”Server=.\SQLEXPress;uid=sa;pwd=password;Da

    2022年8月31日
    2
  • 用数据说话,外贸B2C产品选择(上篇)-热门搜索法

    用数据说话,外贸B2C产品选择(上篇)-热门搜索法

    2022年1月30日
    57
  • leetcode官网_leetcode有多少题

    leetcode官网_leetcode有多少题leetcode378. Kth Smallest Element in a Sorted Matrix

    2022年4月21日
    82
  • 课程表app源码_课程表模板excel

    课程表app源码_课程表模板excel快乐的时光过得特别快,很快各位学生党就要迎来新学期了。课程表对学生的意义不言而喻,特别是对作息自理的大学生来说,没课程表不知道要不要上课丝毫不奇怪,这时在手机上装一个课程表App就省事多了。课程表App为数不少,但你听说过能够撩学妹泡妞的课程表App吗?今天介绍的这款课程格子,就有这么个功能。软件名称:课程格子软件版本:3.00官方版软件大小:5.98MB软件授权:免费适用平台:Android实…

    2022年10月4日
    2
  • 兄弟1218无线打印服务器错误,兄弟无线打印机无法打印怎么办?「建议收藏」

    兄弟1218无线打印服务器错误,兄弟无线打印机无法打印怎么办?「建议收藏」在使用打印机的过程中,打印失败是很常见的。互联网上有很多解决方案,但由于产品型号不同,解决方案并不通用,可能并不适合每台机器。今天,一秀。com的边肖将与你分享我哥哥的无线打印机无法打印的解决方案。别错过了!如果打印机无法打印,请首先确保打印机电器的电源线插入墙壁插座,并按下位于打印机顶部的“开/关”键。如果打印机有电源,请判断打印机是否在线。单击桌面上的开始按钮,然后选择打印机和传真。右键单击打…

    2022年5月30日
    136
  • Mac突然连不上WiFi解决步骤「建议收藏」

    Mac突然连不上WiFi解决步骤「建议收藏」事件描述:上午用图书馆无线看电视过程中,莫名就网断了,开始以为是图书馆网问题,后来手机开热点也无法连接。去年刚买Mac时也出现过这种问题,后来换了主板,心慌还以为又要去修理了o(╯□╰)o 开始无用尝试部分: 1.打开设置-网络-位置,更改为自动 2.关机,立即同时按下command+option+R+P,听到三声后松手 解决步骤:移除网络配置和偏好文件 手动删除网络plist…

    2022年6月18日
    46

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号