java 多線程定時(shí)任務(wù)

文章轉(zhuǎn)載自:https://blog.csdn.net/qq_36226120/article/details/81866801

一、概述

New Thread的弊端如下:
  a、每次New Thread新建對(duì)象性能差。
  b、線程缺乏統(tǒng)一的管理,可能無(wú)限制的新建線程,相互之間競(jìng)爭(zhēng),極可能占用過(guò)多的系統(tǒng)資源導(dǎo)致死機(jī) 或者 OOM。
  c、缺乏更多功能,如定時(shí)執(zhí)行、定期執(zhí)行、線程中斷。

Java提供的四種線程池的好處在于:
  a、重用存在的線程,減少對(duì)象創(chuàng)建、消亡的開(kāi)銷,性能佳。
  b、可有效控制最大并發(fā)線程數(shù)、提供系統(tǒng)資源的使用率,同時(shí)避免過(guò)多資源競(jìng)爭(zhēng),避免堵塞。
  c、提供定時(shí)執(zhí)行、定期執(zhí)行、單線程、并發(fā)數(shù)控制等功能。

二、Executors 創(chuàng)建線程池

Java通過(guò)Executors提供四種線程池,分別為:

newCachedThreadPool創(chuàng)建一個(gè)可緩存線程池,如果線程池長(zhǎng)度超過(guò)處理需要,可靈活回收空閑線程,若無(wú)可回收,則新建線程。
newFixedThreadPool創(chuàng)建一個(gè)定長(zhǎng)線程池,可控制線程最大并發(fā)數(shù),超出的線程會(huì)在隊(duì)列中等待,表示同一時(shí)刻只能有這么大的并發(fā)數(shù)
newScheduledThreadPool創(chuàng)建一個(gè)定長(zhǎng)線程池,支持定時(shí)及周期性任務(wù)執(zhí)行。
newSingleThreadExecutor創(chuàng)建一個(gè)單線程化的線程池,它只會(huì)用唯一的工作線程來(lái)執(zhí)行任務(wù),保證所有任務(wù)按照指定順序(FIFO, LIFO, 優(yōu)先級(jí))執(zhí)行。

三、ThreadPoolExecutor 創(chuàng)建線程池

線程池不建議使用Executors去創(chuàng)建:

ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();

而是通過(guò)ThreadPoolExecutor的方式,這樣的處理方式讓寫的同學(xué)更加明確線程池的運(yùn)行規(guī)則,規(guī)避資源耗盡的風(fēng)險(xiǎn)。 說(shuō)明:Executors各個(gè)方法的弊端:
  1、newFixedThreadPool和newSingleThreadExecutor:
?? 主要問(wèn)題是堆積的請(qǐng)求處理隊(duì)列可能會(huì)耗費(fèi)非常大的內(nèi)存,甚至OOM。
  2、newCachedThreadPool和newScheduledThreadPool:
?? 主要問(wèn)題是線程數(shù)最大數(shù)是Integer.MAX_VALUE,可能會(huì)創(chuàng)建數(shù)量非常多的線程,甚至OOM。

這里介紹三種創(chuàng)建線程池的方式:

Example 1:

// org.apache.commons.lang3.concurrent.BasicThreadFactory
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());

Example 2:

ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build();
 
    //Common Thread Pool
    ExecutorService pool = new ThreadPoolExecutor(5, 200,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
 
    pool.execute(()-> System.out.println(Thread.currentThread().getName()));
    pool.shutdown();//gracefully shutdown

Example 3:

   <bean id="userThreadPool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <property name="corePoolSize" value="10" />
        <property name="maxPoolSize" value="100" />
        <property name="queueCapacity" value="2000" />
        <property name="threadFactory" value= threadFactory />
        <property name="rejectedExecutionHandler">
            <ref local="rejectedExecutionHandler" />
        </property>
    </bean>
    //in code
    userThreadPool.execute(thread);

  
例子:

public class ThreadPoolHelper {
 
    private static final Logger logger = Logger.getLogger(ThreadPoolHelper.class);
 
    private static final int POOL_SIZE = 40;//線程池大小
 
    //訂單任務(wù)線程池
 
    private static ThreadPoolExecutor comitTaskPool =(ThreadPoolExecutor) new ScheduledThreadPoolExecutor(POOL_SIZE,
            new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
 
 
    /**
     * 執(zhí)行訂單任務(wù)
     *
     * @param comitTask
     */
    public static void executeTask(Runnable comitTask) {
        comitTaskPool.execute(comitTask);
        logger.debug("【線程池任務(wù)】線程池中線程數(shù):" + comitTaskPool.getPoolSize());
        logger.debug("【線程池任務(wù)】隊(duì)列中等待執(zhí)行的任務(wù)數(shù):" + comitTaskPool.getQueue().size());
        logger.debug("【線程池任務(wù)】已執(zhí)行完任務(wù)數(shù):" + comitTaskPool.getCompletedTaskCount());
    }
 
 
    /**
     * 關(guān)閉線程池
     */
    public static void shutdown() {
        logger.debug("shutdown comitTaskPool...");
        comitTaskPool.shutdown();
        try {
            if (!comitTaskPool.isTerminated()) {
                logger.debug("直接關(guān)閉失敗[" + comitTaskPool.toString() + "]");
                comitTaskPool.awaitTermination(3, TimeUnit.SECONDS);
                if (comitTaskPool.isTerminated()) {
                    logger.debug("成功關(guān)閉[" + comitTaskPool.toString() + "]");
                } else {
                    logger.debug("[" + comitTaskPool.toString() + "]關(guān)閉失敗,執(zhí)行shutdownNow...");
                    if (comitTaskPool.shutdownNow().size() > 0) {
                        logger.debug("[" + comitTaskPool.toString() + "]沒(méi)有關(guān)閉成功");
                    } else {
                        logger.debug("shutdownNow執(zhí)行完畢,成功關(guān)閉[" + comitTaskPool.toString() + "]");
                    }
                }
            } else {
                logger.debug("成功關(guān)閉[" + comitTaskPool.toString() + "]");
            }
        } catch (InterruptedException e) {
            logger.warn("接收到中斷請(qǐng)" + comitTaskPool.toString() + "停止操作");
        }
    }
}

  
定時(shí)任務(wù):

ScheduledFuture<?> scheduleAtFixedRate?(Runnable command, 
                                       long initialDelay,
                                       long period,
                                       TimeUnit unit)

//command - 要執(zhí)行的任務(wù)
//initialDelay - 延遲第一次執(zhí)行的時(shí)間
//period - 連續(xù)執(zhí)行之間的時(shí)期
//unit - initialDelay和period參數(shù)的時(shí)間單位

ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor (1,
                    new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
            executorService.scheduleAtFixedRate(() -> {
                //執(zhí)行的任務(wù)
            },1000,5000, TimeUnit.HOURS);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容