Java programming logic (80) - regular tasks of those pits

This section examines the timing of the task, the task of the timing scenarios is very large, such as:

  • Alarm clock program or task reminders, or alerts also specify the time Jiaochuang credit card on a specified date
  • Monitoring system, from time to time under the system data acquisition, alarm for abnormal events
  • Statistical system, generally in the morning some time statistical data of various indicators yesterday

In Java, there are two ways to achieve timing tasks:

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

Their basic usage is relatively simple, but if you do not know enough about them, it is very easy to fall into the trap of some of them, here, we have to introduce their usage, as well as those principles pit.

Hours 和 Hours Task

Basic Usage

TimerTask represents timing task, it is an abstract class that implements the Runnable, timing task requires specific class inheritance, implement the run method.

Timer is a concrete class, which is responsible for the timing and scheduling of tasks performed, it has the following main methods: 

Copy the code
// specify an absolute time in time to run the task task 
public void Schedule (TimerTask task, a Date time) 
// delay after delay milliseconds task to run the task at the present time 
public void schedule (TimerTask task, long delay) 
Repeat // fixed delay , first scheduled execution time of firstTime, after a planned execution time before a "real" execution time plus period 
public void Schedule (TimerTask Task, a Date firstTime, Long period) 
// repeat the same fixed delay, the first execution time is the current time plus Delay 
public void Schedule (TimerTask Task, Long Delay, Long period) 
// repeat fixed frequency, first scheduled execution time of firstTime, after a planned execution time of the previous " plan "execution time plus period 
public void scheduleAtFixedRate (TimerTask Task, a Date firstTime, Long period) 
// repeat the same fixed frequency, the first implementation of the plan for the current time plus the delay time 
public void scheduleAtFixedRate (TimerTask task, long delay , long period)
Copy the code

Note that a fixed delay (fixed-delay) with a fixed frequency difference (fixed-rate), are repeatedly performed, but a relatively task execution time is not the same, the fixed delay, which is based on the last task the "real" execution time to count, if for some reason, the last mission delayed, then this mission will be delayed, while the fixed-frequency operation will try to make up enough times.

Also, note that if the first scheduled execution time firstTime is a past time, the task will run immediately, for a fixed delay task, the next task will be calculated based on the first execution time, and for fixed the frequency of the task, it will start counting from the firstTime, it is possible to add or after a period of time in the past, so that continuous operation many times, until the time exceeds the current time.

Our next through some simple examples specific point of view.

A basic example

Look at a simple example:

Copy the code
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();
    }
}
Copy the code

Create a Timer object, run DelayTask 1 second, and finally call the cancel method Timer cancel all scheduled tasks.

See simple example of a fixed delay:

Copy the code
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);
    }
}
Copy the code

There are two timing task, the first run time, but it takes 5 seconds, the second is repeatedly executed, once a second, the first to run. Run the program, you will find the second task will only start running after the end of the first task run, run once a second.

Alternatively, if the above code is a fixed frequency, i.e., the code becomes:

Copy the code
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);
    }
}
Copy the code

Run the program, the same second task will only run at the end of the first task to run, but the number is not running before it will fill up, all of a sudden run five times, output similar to the following:

Copy the code
long running finished
1489467662330
1489467662330
1489467662330
1489467662330
1489467662330
1489467662419
1489467663418
Copy the code

Fundamental

Internal Timer consists of two parts, the task queue and Timer thread. Task queue is a priority queue heap-based implementation, according to the time of the next execution prioritize. Timer thread is responsible for the implementation of all scheduled tasks, needs to be emphasized that a Timer object has only one Timer thread, so, for the above example, the task will be delayed.

Timer is a thread main loop, take the job from the queue, the queue if there are tasks and planned execution time is less than equal to the current time, it is executed, if there are no tasks in the queue or not to delay the first task, to sleep. If during sleep queue to add a new task and the new task is the first task, Timer thread will be awakened and re-checked.

Before performing the task, Timer thread determines whether a task is periodic tasks, and if so, set the time of the next execution and added to the priority queue for a fixed delay task, the next execution time plus the current time period, for a fixed frequency of the task, the next execution time is execution time of the last plan plus period.

It should be stressed that the plan is the next task before the execution of the current task is made, for the fixed delay task, a relative of the current delay time before task execution, task execution rather than later, and talk back calculation ScheduledExecutorService fixed delay is different to a calculation method which is more consistent with normal expectations.

On the other hand, for a fixed frequency of the task, it is always based on the first of the planned program, therefore, it is likely to be the case in the previous example to perform many missions at once appeared.

Endless loop

A Timer object has only one Timer thread, which means that regular tasks can not take too long, but can not be an infinite loop, look at an example:

Copy the code
public class EndlessLoopTimer {
    static class LoopTask extends TimerTask {

        @Override
        public void run() {
            while (true) {
                try {
                    // ... 执行任务
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // 永远也没有机会执行
    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);
    }
}
Copy the code

The first timed task is an infinite loop, the timing of the subsequent task ExampleTask will never have a chance to perform.

Exception Handling

About Timer thread, also we need to emphasize a very important point in the implementation of any method run a task, once run throwing an exception, Timer thread will quit so that all scheduled tasks will be canceled. We look at a simple example:

Copy the code
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);
    }
}
Copy the code

TaskA expected to perform once per second, but TaskB will throw an exception, leading to the scheduled task is canceled, the program terminates, the screen output is:

Copy the code
task A
task A
task B
Exception 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)
Copy the code

So, if you want each scheduled tasks do not interfere with each other, be sure to catch all exceptions in the run method.

summary

Can be seen, the basic use of Timer / TimerTask is relatively simple, but we need to pay attention to:

  • Behind only one thread is running
  • Task is delayed after a fixed frequency, may be immediately executed many times, the number of times up enough
  • Delay task relatively fixed delay time before the task is executed
  • Do not use an infinite loop in timed tasks
  • An unhandled exception timed task causes all regular tasks were canceled

ScheduledExecutorService   

Interfaces and class definitions

Due to some problems Timer / TimerTask's, Java and introduction of contract ScheduledExecutorService, it is an interface, which is defined as:

Copy the code
The ScheduledExecutorService interface the extends ExecutorService {public 
    // single, run-command after a time delay 
    public a ScheduledFuture Schedule (the Runnable command, Long delay, TimeUnit Unit) <?>; 
    // single, run-after a time delay Callable 
    public <V> a ScheduledFuture <V> Schedule (a Callable <V> Callable, Long Delay, TimeUnit Unit); 
    // fixed frequency is repeatedly executed 
    public ScheduledFuture scheduleAtFixedRate (Runnable command, long initialDelay, long period, TimeUnit unit) <?>; 
    // repeat the fixed delay 
    public a ScheduledFuture scheduleWithFixedDelay (the Runnable Command, the initialDelay Long, Long delay, TimeUnit Unit) <?>; 
}
Copy the code

Their return types are ScheduledFuture, it is an interface that extends the Future and Delayed, does not define additional methods. Most of these methods Timer semantics are substantially similar. For fixed-frequency task, after the first execution time of the initialDelay, the second time initialDelay + period, the third initialDelay + 2 * period, and so on. However, for a fixed delay task, which is to start from the task execution count, for the first time after initialDelay, for the second time after the end of the first tasks performed plus delay. Unlike Timer, it does not support an absolute time as the time of the first run.

ScheduledExecutorService main implementation class is ScheduledThreadPoolExecutor, which is a subclass of the thread pool ThreadPoolExecutor, is that its main constructor thread pool implementation is based on:

public ScheduledThreadPoolExecutor(int corePoolSize) 

In addition, construction methods can take ThreadFactory and RejectedExecutionHandler, meaning ThreadPoolExecutor, we will not go into details.

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

Executors factory class provides some convenient way to facilitate the creation of a ScheduledThreadPoolExecutor, as follows:

Copy the code
// single-threaded task execution timing service 
public static ScheduledExecutorService newSingleThreadScheduledExecutor () 
public static ScheduledExecutorService newSingleThreadScheduledExecutor (ThreadFactory threadFactory) 
// multi-threaded task execution timing service 
public static ScheduledExecutorService newScheduledThreadPool (int corePoolSize) 
public static ScheduledExecutorService newScheduledThreadPool (int corePoolSize, ThreadFactory threadFactory )
Copy the code

A basic example

Because you can have multiple threads of execution scheduled task, the task will not generally be the task of a long-running delays, for example, for the previous TimerFixedDelay, if read as follows:

Copy the code
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);
    }
}
Copy the code

Executed again, the second task will not be the first task is delayed.

In addition, different Timer, exceptions will not result in a single timing tasks throughout the scheduled task was canceled, even if only one thread behind the mission, we look at an example:

Copy the code
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);
    }
}
Copy the code

TaskA and TaskB are executed once per second, two seconds after TaskB executed, but the execution on a throw, the output screen similar to the following:

Copy the code
task A
task A
task B
task A
task A
...
Copy the code

This shows that regular tasks TaskB was canceled, but TaskA not be affected, even if they are performed by the same thread. However, it should be emphasized that the Timer different, no exception is thrown, TaskB exception was not reflected anywhere. So, with Timer tasks similar, you should catch all exceptions.

Fundamental

ScheduledThreadPoolExecutor realization of ideas with Timer is basically similar, there is a heap-based priority queue, save the scheduled task to be performed, its main difference is:

  • Behind it is the thread pool, you can have multiple threads of execution tasks
  • It is time to set the next execution of the task after the execution, for a fixed delay of more reasonable task
  • Task execution thread will capture all the tasks performed in the abnormal changes will not affect the timing of other tasks scheduled task, but the task is no longer the exception occurred is rescheduled, even if it is a repeat task

summary

This section describes two implementations of Java in regular tasks, Timer and ScheduledExecutorService, need to pay special attention to some of the pitfalls Timer, the practice is recommended ScheduledExecutorService.

Their common limitation is that the timing is not competent complex task scheduling, for example, every Monday and Wednesday from 18:00 to 22:00 in the evening, performed once every half hour. Similar to this demand, we can use the date and time prior to treatment in Section 32 and Section 33 describes, or use a more powerful third-party libraries, such as Quartz (http://www.quartz-scheduler.org/ ).

In concurrent applications, generally we should try to take advantage of high-level services, such as various concurrent containers described in the previous section, service and task execution thread pool, to avoid synchronization between threads and their own management, but in individual cases their own thread management and synchronization is necessary, then, in addition to the previous section introduced the use of synchronized, wait / notify, and display basic tools lock condition, Java and the contract also provides some advanced synchronization and collaboration tools to facilitate the achievement concurrent applications, let us in the next section to learn about them.

Guess you like

Origin www.cnblogs.com/ivy-xu/p/12375495.html