Thinking logic of computer programs (80) and thinking 80

Source: Internet
Author: User

Thinking logic of computer programs (80) and thinking 80

This section describes scheduled tasks. There are many application scenarios for scheduled tasks, such:

  • An alarm program or task reminder. You can call a bed at a specified time or return a credit card on a specified date.
  • The monitoring system collects system data at intervals to trigger alarms for abnormal events.
  • Statistical System, which usually collects various data indicators of yesterday at a certain time in the early morning.

In Java, there are two ways to implement scheduled tasks:

  • Use Timer and TimerTask in the java. util package
  • Use ScheduledExecutorService in the Java concurrent package

Their basic usage is relatively simple, but if you do not know enough about them, it is easy to fall into some of these traps. below, let's introduce their usage, principles, and pitfalls.

Timer and TimerTask

Basic usage

TimerTask is a scheduled task. It is an abstract class that implements Runnable. A specific scheduled task must inherit this class to implement the run method.

Timer is a specific class that schedules and executes scheduled tasks. It has the following main methods:

// Run the task taskpublic void schedule (TimerTask task, Date time) at the specified absolute time // run the task taskpublic void schedule (TimerTask task, long delay) after the current delay of delay milliseconds) // fixed latency for repeated execution. The first scheduled execution time is firstTime, And the last scheduled execution time is the previous "actual" execution time plus periodpublic void schedule (TimerTask task, Date firstTime, long period) // It is also a fixed delay for repeated execution. The first execution time is the current time plus delaypublic void schedule (TimerTask task, long delay, long period) // fixed frequency for repeated execution, the first scheduled execution time is firstTime, And the last scheduled execution time is the previous scheduled execution time plus periodpublic void scheduleAtFixedRate (TimerTask task, Date firstTime, long period) // repeated execution at a fixed frequency. The first scheduled execution time is the current time plus delaypublic void scheduleAtFixedRate (TimerTask task, long delay, long period)

Pay attention to the difference between fixed latency (fixed-delay) and fixed frequency (fixed-rate). They are all executed repeatedly, but the relative time of the next task is different. For fixed latency, it is calculated based on the "actual" execution time of the previous task. if the task is delayed for some reason, the task will also be delayed, the fixed frequency will try to supplement the running times as much as possible.

In addition, it should be noted that if the first scheduled execution time firstTime is a previous time, the task will run immediately. For tasks with fixed latency, the next task is calculated based on the first execution time. For tasks with a fixed frequency, the task starts from firstTime. It is possible that the period is the past time, and the task runs continuously for many times, until the current time is exceeded.

Let's take a look at some simple examples.

Basic example

Let's look at the simplest example:

public class BasicTimer {    static class DelayTask extends TimerTask {                @Override        public void run() {            System.out.println("delayed task");        }    }        public static void main(String[] args) throws InterruptedException {        Timer timer = new Timer();        timer.schedule(new DelayTask(), 1000);        Thread.sleep(2000);        timer.cancel();    }}

Create a Timer object, run DelayTask in 1 second, and call the cancel Method of Timer to cancel all scheduled tasks.

Let's look at a simple example of fixed latency:

public class TimerFixedDelay {    static class LongRunningTask extends TimerTask {        @Override        public void run() {            try {                Thread.sleep(5000);            } catch (InterruptedException e) {            }            System.out.println("long running finished");        }    }    static class FixedDelayTask extends TimerTask {        @Override        public void run() {            System.out.println(System.currentTimeMillis());        }    }    public static void main(String[] args) throws InterruptedException {        Timer timer = new Timer();        timer.schedule(new LongRunningTask(), 10);        timer.schedule(new FixedDelayTask(), 100, 1000);    }}

There are two scheduled tasks. The first task is run once, but it takes 5 seconds. The second task is run repeatedly, once every 1 second, and the first task is run first. Run this program and you will find that the second task starts to run only after the first task is completed.

If the above Code is replaced with a fixed frequency, that is, the code changes:

public class TimerFixedRate {    static class LongRunningTask extends TimerTask {        @Override        public void run() {            try {                Thread.sleep(5000);            } catch (InterruptedException e) {            }            System.out.println("long running finished");        }    }    static class FixedRateTask extends TimerTask {        @Override        public void run() {            System.out.println(System.currentTimeMillis());        }    }    public static void main(String[] args) throws InterruptedException {        Timer timer = new Timer();        timer.schedule(new LongRunningTask(), 10);        timer.scheduleAtFixedRate(new FixedRateTask(), 100, 1000);    }}

Run the program. The second task will run only after the first task is finished, but it will overwrite the number of times it has not been run and run five times at once, the output is similar to the following:

long running finished1489467662330148946766233014894676623301489467662330148946766233014894676624191489467663418

Basic Principles

Timer consists of two parts: task queue and Timer thread. A task queue is a heap-based priority queue, Which is prioritized according to the next execution time. The Timer thread is responsible for executing all scheduled tasks. It should be emphasized that a Timer object has only one Timer thread. Therefore, for the above example, the task will be delayed.

The Timer thread is a loop that obtains a task from the queue. If there is a task in the queue and the scheduled execution time is less than or equal to the current time, it will be executed, if there is no task in the queue or the delay of the first task has not arrived, you will be able to sleep. If a new task is added to the squadron column during sleep and the new task is the first task, the Timer thread will be awakened and re-checked.

Before executing a task, the Timer thread determines whether the task is a periodic task. If yes, it sets the next execution time and adds it to the priority queue. For tasks with fixed latency, the next execution time is the current time plus period (period). For tasks with a fixed frequency, the next execution time is the last scheduled execution time plus period (period.

It should be emphasized that the plan for the next task is made before the current task is executed. For tasks with fixed latency, the latency is relative to the current time before the task is executed, rather than after the task is executed, this is different from the fixed delay Calculation Method of ScheduledExecutorService described later. The latter calculation method is more in line with general expectations.

On the other hand, for a fixed frequency task, it is always based on the first plan, so it is very likely that the previous example will suddenly execute many tasks.

Endless loop

A Timer object has only one Timer thread, which means that the scheduled task cannot take too long or be an infinite loop. For example:

Public class EndlessLoopTimer {static class LoopTask extends TimerTask {@ Override public void run () {while (true) {try {//... run the task Thread. sleep (1000);} catch (InterruptedException e) {e. printStackTrace () ;}}}// there is never a chance to execute static class ExampleTask extends TimerTask {@ Override public void run () {System. out. println ("hello") ;}} public static void main (String [] args) throws InterruptedException {Timer timer = new Timer (); timer. schedule (new LoopTask (), 10); timer. schedule (new ExampleTask (), 100 );}}

The first scheduled task is an infinite loop, and the subsequent scheduled task ExampleTask will never be executed.

Exception Handling

The Timer thread also needs to be emphasized. When executing the run method of any task, the Timer thread will exit once the run throws an exception, all scheduled tasks are canceled. Let's look at a simple example:

public class TimerException {    static class TaskA extends TimerTask {                @Override        public void run() {            System.out.println("task A");        }    }        static class TaskB extends TimerTask {                @Override        public void run() {            System.out.println("task B");            throw new RuntimeException();        }    }    public static void main(String[] args) throws InterruptedException {        Timer timer = new Timer();        timer.schedule(new TaskA(), 1, 1000);        timer.schedule(new TaskB(), 2000, 1000);    }}

Task KA is expected to run once per second, but task kb throws an exception, causing the entire scheduled task to be canceled, the program to terminate, and the screen output is:

task Atask Atask BException in thread "Timer-0" java.lang.RuntimeException    at laoma.demo.timer.TimerException$TaskB.run(TimerException.java:21)    at java.util.TimerThread.mainLoop(Timer.java:555)    at java.util.TimerThread.run(Timer.java:505)

Therefore, if you want the scheduled tasks to not interfere with each other, you must capture all exceptions in the run method.

Summary

We can see that the basic use of Timer/TimerTask is relatively simple, but we need to note:

  • Only one thread is running.
  • After a fixed frequency task is delayed, it may be executed multiple times immediately and the number of times is supplemented.
  • The latency of a fixed delayed task is relative to the time before the task is executed.
  • Do not use infinite loops in scheduled tasks
  • An unprocessed exception of a scheduled task will cause all scheduled tasks to be canceled.

ScheduledExecutorService

Interface and Class Definition

Due to some Timer/TimerTask problems, ScheduledExecutorService is introduced in Java concurrent package. It is an interface defined:

Public interface ScheduledExecutorService extends ExecutorService {// One-time execution, run command public ScheduledFuture after the specified delay <?> Schedule (Runnable command, long delay, TimeUnit unit); // run callable public <V> ScheduledFuture <V> schedule (Callable <V> callable, long delay, TimeUnit unit); // execute public ScheduledFuture repeatedly at a fixed frequency <?> ScheduleAtFixedRate (Runnable command, long initialDelay, long period, TimeUnit unit); // execute public ScheduledFuture repeatedly at fixed latency <?> ScheduleWithFixedDelay (Runnable command, long initialDelay, long delay, TimeUnit unit );}

Their return types are ScheduledFuture, which is an interface that extends Future and Delayed without defining additional methods. Most of the semantics of these methods is similar to that of Timer. For a fixed frequency task, after the first execution time is initialDelay, the second is initialDelay + period, the third is initialDelay + 2 * period, and so on. However, for a fixed latency task, it starts from the execution of the task. After the first time it is initialDelay, the second time it is added after the execution of the first task. Unlike Timer, it does not support absolute time as the first running time.

The main implementation class of ScheduledExecutorService is ScheduledThreadPoolExecutor. It is a subclass of ThreadPoolExecutor in the thread pool and implemented based on the thread pool. Its main construction method is:

public ScheduledThreadPoolExecutor(int corePoolSize) 

In addition, there are constructor parameters ThreadFactory and RejectedExecutionHandler which are similar to ThreadPoolExecutor.

Its task queue is an unbounded priority queue, so the maximum number of threads has no effect on it. Even if corePoolSize is set to 0, it will run at least one thread.

The factory class Executors also provides some convenient methods to facilitate the creation of ScheduledThreadPoolExecutor, as shown below:

// Single-threaded scheduled task execution service public static ScheduledExecutorService Invocation () public static ScheduledExecutorService Invocation (ThreadFactory threadFactory) // multithreading scheduled task execution service public static ScheduledExecutorService newScheduledThreadPool (int corePoolSize) public static ScheduledExecutorService newScheduledThreadPool (int corePoolSize, ThreadFactory threadFactory)

Basic example

Since there can be multiple threads to execute scheduled tasks, generally the task will not be delayed by a long-running task. For example, for the previous TimerFixedDelay, if it is changed:

public class ScheduledFixedDelay {    static class LongRunningTask implements Runnable {        @Override        public void run() {            try {                Thread.sleep(5000);            } catch (InterruptedException e) {            }            System.out.println("long running finished");        }    }    static class FixedDelayTask implements Runnable {        @Override        public void run() {            System.out.println(System.currentTimeMillis());        }    }    public static void main(String[] args) throws InterruptedException {        ScheduledExecutorService timer = Executors.newScheduledThreadPool(10);        timer.schedule(new LongRunningTask(), 10, TimeUnit.MILLISECONDS);        timer.scheduleWithFixedDelay(new FixedDelayTask(), 100, 1000,                TimeUnit.MILLISECONDS);    }}

If you execute the task again, the second task will not be delayed by the first task.

In addition, unlike Timer, the exception of a single scheduled task will no longer lead to the cancellation of the entire scheduled task. Even if there is only one thread running the task, let's take an example:

public class ScheduledException {    static class TaskA implements Runnable {        @Override        public void run() {            System.out.println("task A");        }    }    static class TaskB implements Runnable {        @Override        public void run() {            System.out.println("task B");            throw new RuntimeException();        }    }    public static void main(String[] args) throws InterruptedException {        ScheduledExecutorService timer = Executors                .newSingleThreadScheduledExecutor();        timer.scheduleWithFixedDelay(new TaskA(), 0, 1, TimeUnit.SECONDS);        timer.scheduleWithFixedDelay(new TaskB(), 2, 1, TimeUnit.SECONDS);    }}

Task ka and task Kb are executed once per second, and task KB is executed two seconds later, but an exception is thrown when executed. The screen output is similar to the following:

task Atask Atask Btask Atask A...

This indicates that task KB is canceled, but task KA is not affected, even if they are executed by the same thread. However, it should be emphasized that, unlike Timer, no exceptions are thrown, and TaskB exceptions are not reflected anywhere. Therefore, similar to tasks in Timer, all exceptions should be caught.

Basic Principles

The implementation idea of ScheduledThreadPoolExecutor is similar to that of Timer. There is a heap-based priority queue that stores scheduled tasks to be executed. The main differences are:

  • It is backed by a thread pool that can have multiple threads to execute tasks.
  • It sets the next execution time after the task is executed, which is more reasonable for tasks with fixed latency.
  • The task execution thread captures all exceptions in the task execution process. A scheduled task exception does not affect other scheduled tasks, but the abnormal tasks are no longer rescheduled, even if it is a duplicate task.

Summary

This section describes two implementation methods for scheduled tasks in Java: Timer and ScheduledExecutorService. Pay special attention to some Timer traps. We recommend that you use ScheduledExecutorService in practice.

Their common limitations are that they are not competent for complex scheduled tasks. For example, they are executed every Monday and Wednesday from. For requirements similar to this, you can take advantage of the date and time processing methods we introduced in sections 32 and 33, or take advantage of more powerful third-party libraries such as Quartz (http://www.quartz-scheduler.org /).

In concurrent applications, we should generally make full use of high-level services, such as the various concurrent containers, task execution services, and thread pools described in the previous chapter, avoid managing threads and synchronizing them by yourself, but in some cases, managing threads and synchronizing by yourself is required. In this case, in addition to using the synchronized, wait/notify, basic tools such as display locks and conditions. Java also provides some advanced synchronization and collaboration tools to facilitate concurrent applications. Let's take a look at them in the next section.

(As in other sections, all the code in this section is in the https://github.com/swiftma/program-logic)

----------------

For more information, see the latest article. Please pay attention to the Public Account "lauma says programming" (scan the QR code below), from entry to advanced, ma and you explore the essence of Java programming and computer technology. Retain All copyrights with original intent.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.