Java教程

Java并发编程之计划任务ScheduledExecutor

本文主要是介绍Java并发编程之计划任务ScheduledExecutor,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

计划任务之ScheduledExecutorService

在讲ScheduledExecutorService之前先来看看另外一个定时任务Timer的使用

  • 定时任务Timer

Timer类能够设置定时任务的相应方法不多,并且不够灵活,在高并发场景下效率不高。

Java并发编程之计划任务ScheduledExecutor

 

这里以周期执行任务方法为例来看Timer内部是如何工作的

示例:

public class TimerDemo {
    
    public static void main(String[] args) {
        Timer timer = new Timer() ;
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()) ;
            }
        }, new Date(), 2000);
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + ", task...") ;
            }
        }, new Date(), 2000);
    }
    
}

这里很简单添加了2个周期任务都是每2秒输出当前线程的名称信息。

Java并发编程之计划任务ScheduledExecutor

 

从控制台也能看出来,发现2个任务都是同一个线程来完成调度的。

在Timer类中有个成员变量:

Java并发编程之计划任务ScheduledExecutor

 

这个类继承了Thread类。

new Timer时设置线程名称并启动线程:

Java并发编程之计划任务ScheduledExecutor

 

启动线程后执行run方法:

Java并发编程之计划任务ScheduledExecutor

 

mainLoop方法:

Java并发编程之计划任务ScheduledExecutor

 

该方法死循环不停的从queue中获取任务执行。

当Timer执行时出现异常时会发生什么呢?

public class TimerDemo {
    static int a = 10 ;
    public static void main(String[] args) {
        Timer timer = new Timer() ;
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                if (a == 12) {
                    throw new RuntimeException("发生错误") ;
                }
                a++ ;
                System.out.println(Thread.currentThread().getName()) ;
            }
        }, new Date(), 2000);
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + ", task...") ;
            }
        }, new Date(), 2000);
    }
}

执行结果:

Java并发编程之计划任务ScheduledExecutor

 

1、当发生异常时整个Timer就停止了,这肯定不是我们想要的。

2、Timer对调度的支持是基于绝对时间的,而不是相对时间,所以它对系统时间的改变非常敏感。

知道了Timer的缺陷,接下来看ScheduledExecutorService


  • ScheduledExecutorService任务计划

ScheduledExecutorService主要功能就是可以将定时任务与线程池功能结合使用。

ScheduledExecutorService是个接口它有一个实现类
ScheduledThreadPoolExecutor


ScheduledThreadPoolExecutor的父类是ThreadPoolExecutor。


ScheduledThreadPoolExecutor类方法:

Java并发编程之计划任务ScheduledExecutor

 

有些方法是重写了父类的方法。如:submit,shutdown等方法。

通过Callable来执行延迟任务

示例:

public class ScheduledExecutorServiceDemo {
    
    public static void main(String[] args) throws Exception {
        ScheduledExecutorService sch = new ScheduledThreadPoolExecutor(5) ; 
        ScheduledFuture<String> f1 = sch.schedule(() -> {
            System.out.println(Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ;
            return "Task1" ;
        }, 5, TimeUnit.SECONDS) ;
        ScheduledFuture<String> f2 = sch.schedule(() -> {
            System.out.println(Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ;
            return "Task2" ;
        }, 6, TimeUnit.SECONDS) ;
        System.out.println(f1.get()) ;
        System.out.println(f2.get()) ;
    }
    
}

执行结果:

Java并发编程之计划任务ScheduledExecutor

 

根据运行结果发现两个任务是同时执行的,第二个任务是又过了1秒就执行了。也就是多个任务同时执行时他们的起始时间都是一样的并不是一个执行完后另外一个要从0开始再计时。

通过Runnable来执行延迟任务

示例:

public class ScheduledExecutorServiceDemo2 {
    
    public static void main(String[] args) throws Exception {
        ScheduledExecutorService sch = new ScheduledThreadPoolExecutor(5) ; 
        sch.schedule(() -> {
            System.out.println("A起始时间: " + Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ;
            try {
                TimeUnit.SECONDS.sleep(3) ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("A结束时间: " + Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ;
        }, 2, TimeUnit.SECONDS) ;
        sch.schedule(() -> {
            System.out.println("B起始时间: " + Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ;
            try {
                TimeUnit.SECONDS.sleep(5) ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("B结束时间: " + Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ;
        }, 2, TimeUnit.SECONDS) ;
    }
    
}

执行结果:

Java并发编程之计划任务ScheduledExecutor

 

执行周期性的任务scheduleAtFixedRate

示例(任务执行时间 > 周期时间):

public class ScheduledExecutorServiceDemo3 {
    
    public static void main(String[] args) throws Exception {
        ScheduledExecutorService sch = new ScheduledThreadPoolExecutor(5) ; 
        sch.scheduleAtFixedRate(() -> {
            System.out.println("A起始时间: " + Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ;
            try {
                TimeUnit.SECONDS.sleep(3) ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("A结束时间: " + Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ;
        }, 1, 2, TimeUnit.SECONDS) ;
    }
    
}

执行结果:

Java并发编程之计划任务ScheduledExecutor

 

使用scheduleWithFixedDelay方法实现周期性任务执行

示例:

public class ScheduledExecutorServiceDemo4 {
    
    public static void main(String[] args) throws Exception {
        ScheduledExecutorService sch = new ScheduledThreadPoolExecutor(5) ; 
        sch.scheduleWithFixedDelay(() -> {
            System.out.println("A起始时间: " + Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ;
            try {
                TimeUnit.SECONDS.sleep(1) ;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("A结束时间: " + Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ;
        }, 1, 2, TimeUnit.SECONDS) ;
    }
    
}

执行结果:

Java并发编程之计划任务ScheduledExecutor

 

scheduleWithFixedDelay方法的作用是使得每次任务执行间隔为固定时间也就是scheduleWithFixedDelay方法的倒数第二个参数

Java并发编程之计划任务ScheduledExecutor

 

公众号:Springboot实战案例锦集

这篇关于Java并发编程之计划任务ScheduledExecutor的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!