天天看點

Java高并發程式設計中ScheduledExecutorService的使用及詳細介紹-劉宇一、什麼是ScheduledExecutorService?二、ScheduledThreadPoolExecutor中的方法三、練習

Java高并發程式設計中ScheduledExecutorService的使用及詳細介紹-劉宇

  • 一、什麼是ScheduledExecutorService?
  • 二、ScheduledThreadPoolExecutor中的方法
    • 1、構造方法
    • 2、schedule方法
    • 3、scheduleAtFixedRate方法
    • 4、scheduleWithFixedDelay方法
    • 5、setContinueExistingPeriodicTasksAfterShutdownPolicy方法
    • 6、setExecuteExistingDelayedTasksAfterShutdownPolicy方法
  • 三、練習
    • 1、schedule練習
    • 2、scheduleAtFixedRate練習1
    • 3、scheduleAtFixedRate練習2
    • 4、scheduleWithFixedDelay練習
    • 5、setContinueExistingPeriodicTasksAfterShutdownPolicy練習

作者:劉宇

CSDN部落格位址:https://blog.csdn.net/liuyu973971883

有部分資料參考,如有侵權,請聯系删除。如有不正确的地方,煩請指正,謝謝。

一、什麼是ScheduledExecutorService?

ScheduledExecutorService是基于ExecutorService的功能實作的延遲和周期執行任務的功能。每個任務以及每個任務的每個周期都會送出到線程池中由線程去執行,是以任務在不同周期内執行它的線程可能是不同的。ScheduledExecutorService接口的預設實作類是ScheduledThreadPoolExecutor。在周期執行的任務中,如果任務執行時間大于周期時間,則會以任務時間優先,等任務執行完畢後才會進入下一次周期

二、ScheduledThreadPoolExecutor中的方法

因為ScheduledThreadPoolExecutor繼承了ThreadPoolExecutor類,是以有很多方法都是來自ThreadPoolExecutor類的,這裡就不做解釋了,想了解的兄弟可以看我前面的部落格:點選檢視詳細

1、構造方法

構造一個Schedule線程池,最大線程數為Integer的最大值,線程的空閑時間為0,隊列采用的是DelayedWorkQueue
  • corePoolSize:線程池核心線程數
  • threadFactory:線程工廠
  • handler:任務拒絕政策
ScheduledThreadPoolExecutor(int corePoolSize)
ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory)
ScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler)
ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler)
           

2、schedule方法

延時執行runnable或者callable任務。執行runnable任務時是沒有結果傳回的,那為什麼還會傳回ScheduledFuture,因為我們可以通過Future做一些取消任務等操作。
  • delay:延時的時間
  • unit:時間機關
ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)
<V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit)
           

3、scheduleAtFixedRate方法

固定周期性執行任務,當任務的執行時長大于周期,那麼下一個周期任務将在上一個執行完畢之後馬上執行。
  • command:runnable任務
  • initialDelay:任務首次執行前的延遲時間
  • period:周期時間
  • unit:時間機關

4、scheduleWithFixedDelay方法

固定延時執行任務,也是周期性任務,和scheduleAtFixedRate不同的是:scheduleAtFixedRate當任務執行時間小于周期時間時,此時周期時間到了的時候會進入下一周期,如果任務執行時間大于周期時間時,任務結束後會立即進入下一周期;而scheduleWithFixedDelay是無論你任務時間是否超過,都将會在你任務執行完畢後延遲固定秒數,才會進入下一周期。
  • command:runnable任務
  • initialDelay:任務首次執行前的延遲時間
  • delay:延時時間
  • unit:時間機關

5、setContinueExistingPeriodicTasksAfterShutdownPolicy方法

預設為false。線上程池執行shutdown方法後是否繼續執行scheduleAtFixedRate方法和scheduleWithFixedDelay方法送出的任務

6、setExecuteExistingDelayedTasksAfterShutdownPolicy方法

預設為true,線上程池執行shutdown方法後,需要等待目前正在等待的任務的和正在運作的任務被執行完,然後程序被銷毀。為false時,表示放棄等待的任務,正在運作的任務一旦完成,則程序被銷毀。

三、練習

1、schedule練習

本次練習中出來schedule的練習外,還包含了如何取消任務。
package com.brycen.part3.threadpool;

import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ScheduledExecutorServiceExample {
    public static void main(String[] args) {
        ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(2);
        //2秒後執行runnable任務
        scheduledThreadPoolExecutor.schedule(() -> {
            System.out.println("This is runable1 task");
        }, 2, TimeUnit.SECONDS);

        //送出一個2秒後才執行的runnable任務
        //既然runnable無法傳回結果,為什麼還要有Future呢,因為我們可以通過Future進行取消任務等操作
        ScheduledFuture<?> runnableFuture = scheduledThreadPoolExecutor.schedule(() -> {
            System.out.println("This is runable2 task");
        }, 2, TimeUnit.SECONDS);
        //取消任務
        runnableFuture.cancel(true);

        //休眠3秒,確定上面的任務都被執行完
        mySleep(3);
        System.out.println("========================");
    }
    private static void mySleep(int seconds){
        try {
            TimeUnit.SECONDS.sleep(seconds);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
           

運作結果:

This is runable1 task
========================
           

2、scheduleAtFixedRate練習1

周期性執行某個任務,執行到一定之間後取消任務
package com.test.part3.threadpool;

import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ScheduledExecutorServiceExample2 {
    public static void main(String[] args) {
        ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(2);
        //送出延遲1秒執行,周期為2秒的runnable任務,雖然runnable沒有傳回結果,但是可以通過runnable取消任務
        ScheduledFuture<?> runnableFuture = scheduledThreadPoolExecutor.scheduleAtFixedRate(() -> {
            System.out.println("This is runable task running "+Thread.currentThread().getName());
        }, 1,2, TimeUnit.SECONDS);

        //休眠8秒
        mySleep(8);
        //取消該循壞任務
        runnableFuture.cancel(true);
    }
    private static void mySleep(int seconds){
        try {
            TimeUnit.SECONDS.sleep(seconds);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
           

運作結果:

  • 可以看出每個周期執行的任務并不是同一個線程,周期時間到的時候隻是将任務扔到線程池的任務隊列中由空閑線程擷取它的執行權。
This is runable task running pool-1-thread-1
This is runable task running pool-1-thread-1
This is runable task running pool-1-thread-1
This is runable task running pool-1-thread-2
           

3、scheduleAtFixedRate練習2

逾時的周期性任務
package com.brycen.part3.threadpool;

import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

public class ScheduledExecutorServiceExample3 {
    public static void main(String[] args) {
        ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(2);
        AtomicLong atomicLong = new AtomicLong(0L);
        //送出初始延遲1秒執行,固定周期為2秒的runnable任務
        ScheduledFuture<?> runnableFuture = scheduledThreadPoolExecutor.scheduleAtFixedRate(() -> {
            //記錄目前時間
            Long current = System.currentTimeMillis();
            //判斷是否為第一次運作
            if (atomicLong.get()==0){
                atomicLong.set(current);
                System.out.printf("first running [%d]\n",atomicLong.get());
            }else{
                //記錄與上次的間隔時間
                System.out.printf("running time:[%d]\n",current-atomicLong.get());
            }
            //将目前時間儲存
            atomicLong.set(current);
            //模拟超過固定周期時間
            mySleep(5);
        }, 1,2, TimeUnit.SECONDS);

    }
    private static void mySleep(int seconds){
        try {
            TimeUnit.SECONDS.sleep(seconds);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
           

運作結果:

  • 可以看出,超出周期時間時,任務完成後立即就進入了下一周期
first running [1597659726690]
running time:[5042]
running time:[5001]
running time:[5000]
running time:[5001]
           

4、scheduleWithFixedDelay練習

package com.test.part3.threadpool;

import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

public class ScheduledExecutorServiceExample4 {
    public static void main(String[] args) {
        ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(2);
        AtomicLong atomicLong = new AtomicLong(0L);
        //送出初始延遲1秒執行,延遲為2秒的runnable任務
        ScheduledFuture<?> runnableFuture = scheduledThreadPoolExecutor.scheduleWithFixedDelay(() -> {
            //記錄目前時間
            Long current = System.currentTimeMillis();
            //判斷是否為第一次運作
            if (atomicLong.get()==0){
                atomicLong.set(current);
                System.out.printf("first running [%d]\n",atomicLong.get());
            }else{
                //記錄與上次的間隔時間
                System.out.printf("running time:[%d]\n",current-atomicLong.get());
            }
            //将目前時間儲存
            atomicLong.set(current);
            //模拟超過固定周期時間
            mySleep(5);
        }, 1,2, TimeUnit.SECONDS);

    }
    private static void mySleep(int seconds){
        try {
            TimeUnit.SECONDS.sleep(seconds);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
           

運作結果:

  • 可以看出來,無論你的任務執行多久,在任務執行完畢之後都會延遲一定時間才進入下一周期。
first running [1597659862349]
running time:[7047]
running time:[7002]
running time:[7023]
running time:[7002]
running time:[7003]
           

5、setContinueExistingPeriodicTasksAfterShutdownPolicy練習

package com.brycen.concurrency03.threadpool;

import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ScheduledExecutorServiceExample5 {
	public static void main(String[] args) {
		ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(2);
		//送出固定周期任務
		ScheduledFuture<?> runnableFuture = scheduledThreadPoolExecutor.scheduleAtFixedRate(() -> {
            System.out.println("This is runable task running "+Thread.currentThread().getName());
        }, 1,2, TimeUnit.SECONDS);
		//預設情況關閉線程池後是不允許繼續執行固定周期任務的,所有輸出false
		System.out.println(scheduledThreadPoolExecutor.getContinueExistingPeriodicTasksAfterShutdownPolicy());
		//設定為true
		scheduledThreadPoolExecutor.setContinueExistingPeriodicTasksAfterShutdownPolicy(true);
		//休眠1200毫秒,確定任務被執行
		mySleep(1200);
		//關閉線程池
		scheduledThreadPoolExecutor.shutdown();
		//休眠2000毫秒後檢視線程池狀态
		mySleep(2000);
		//線程池的狀态
		System.out.println("isShutdown:"+scheduledThreadPoolExecutor.isShutdown());
		System.out.println("isTerminating:"+scheduledThreadPoolExecutor.isTerminating());
		System.out.println("isTerminated:"+scheduledThreadPoolExecutor.isTerminated());
	}
	
	private static void mySleep(int milliSeconds){
        try {
            TimeUnit.MILLISECONDS.sleep(milliSeconds);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
           

運作結果:

false
This is runable task running pool-1-thread-1
This is runable task running pool-1-thread-1
isShutdown:true
isTerminating:true
isTerminated:false
This is runable task running pool-1-thread-1
This is runable task running pool-1-thread-1
...