[JavaEE] Multi-threading case - timer

Author homepage:paper jie_blog

Author of this article: Hello everyone, I am paper jie. Thank you for reading this article. Welcome to Yijiansanlian.

This article is in the "JavaEE" column. This column is carefully created for college students and programming novices. The author spent a lot of money (time and energy) to build it and cover all the basic knowledge of MySQL. I hope it can help readers.

Other columns: "MySQL", "C Language", "javaSE", "Data Structure", etc.

Content sharing: This issue will share a multi-threading case - timer

Table of contents

 What is a timer

Timer in Java standard library - Timer

Customize a timer

Timer composition

Description class MyTask

Implement MyTask comparison

The structure of MyTimer class

schedule method

Built-in threads

Thread safety and wait

specific code

Code execution flow


 What is a timer

The timer is a very important component in our programmers' software development. Its function is the same as an alarm clock. When a set time is reached, a specified piece of code needs to be executed. The timer is used in our actual development It is particularly common. For example, a game requires an Internet connection to be used. If no data is returned to the server within 1 second, the timer will take effect, disconnect from the network and try to reconnect.

Timer in Java standard library - Timer

There is a Timer class built into our Java standard library, which is a timer. There is a core method schedule in it, which is used to register tasks. 

There are two parameters in schedule. One is the code that needs to be executed when the time is up, and the second is the time to wait, in milliseconds.

public class ThreadDemo11 {
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("hello 1000");
            }
        }, 1000);
    }
}

Customize a timer

Timer composition

Here a MyTimer class is used to represent the timer

1) A priority queue PriorityQueue is required to store tasks.

2) A MyTask class is needed to describe the task

3) These tasks require time comparison, and the MyTask class needs to implement the Comparable interface.

4) It is necessary to define a built-in thread to continuously scan the task and observe whether the time is up.

5) The core method schedule needs to be implemented to register tasks

Description class MyTask

The Task class is used to describe tasks, which contains a Runnable object and a time timestamp. The code that needs to be executed will be given to the Runnable by passing parameters.

class MyTask3 {
    //
    private long time;
    private Runnable runnable = null;
    public MyTask3(Runnable runnable, long delay) {
        this.runnable = runnable;
        //需要执行的时刻
        this.time = System.currentTimeMillis() + delay;
    }
    //获取时间
    public long getTime() {
        return time;
    }
    //获取需要执行的代码
    public void run() {
        runnable.run();
    }
    
}

Implement MyTask comparison

Because Mytask describes tasks, and these tasks need to be placed in the priority queue for comparison, you need to implement Comparable or a comparator. Here we implement the Comparable interface.

class MyTask3 implements Comparable<MyTask3>{
    //
    private long time;
    private Runnable runnable = null;
    public MyTask3(Runnable runnable, long delay) {
        this.runnable = runnable;
        //需要执行的时刻
        this.time = System.currentTimeMillis() + delay;
    }
    //获取时间
    public long getTime() {
        return time;
    }
    //获取需要执行的代码
    public void run() {
        runnable.run();
    }
    //比较时间快慢方法
    @Override
    public int compareTo(MyTask3 o) {
        return (int)(this.time - o.time);
    }
}

The structure of MyTimer class

The core thing here is the priority queue, priorityQueue, which is used to store our tasks. The object plays a locking role for us later.

class MyTimer3 {
    //用优先级队列来存放任务
    private PriorityQueue<MyTask3> priorityQueue = new PriorityQueue<>();
    //锁对象
    private Object blocker = new Object();
    public void schedule(Runnable runnable, long time) {
        //核心方法
    }
}

schedule method

Here we create a task in the core method schedule, and then put the task into the priority queue.

public void schedule(Runnable runnable, long time) {
        //创建一个任务
        MyTask3 myTask3 = new MyTask3(runnable, time);
        //将创建的任务放入优先级队列中
        priorityQueue.offer(myTask3);
    }

Built-in threads

Here, the built-in thread is put into the constructor, and execution starts as soon as the class is created. Here, a while loop is used to continuously scan.

//内置线程
    public MyTimer3() {
        //创建一个线程
        Thread t = new Thread(() -> {
            //通过while来不断扫描
            while(true) {
                //判断优先级队列是不是空的
                if(priorityQueue.isEmpty()) {
                    //为空就等待
                    //continue;
                }
                //当优先级队列中有任务时,取出任务
                MyTask3 myTask3 = priorityQueue.peek();
                //当前时间
                long time = System.currentTimeMillis();
                //如果到时间了就执行
                if(time >= myTask3.getTime()) {
                    myTask3.run();
                    priorityQueue.take();
                }else {
                    //时间没到等待
                    //continue;
                }
                
            }
        });
        t.start();
    }

Thread safety and wait

It is found here that both the schedule method and the construction method will read and modify the priorityQueue priority queue. Thread safety issues may arise here, and we need to add locks to them. When it is empty, we wait through the wait method and wait for the schedule to be called. The method uses notify to wake it up. When there is an element but the time has not yet arrived, wait is used to wait for a while, and when the time is up, the wait is released.

public void schedule(Runnable runnable, long time) {
        synchronized (blocker) {
            //创建一个任务
            MyTask3 myTask3 = new MyTask3(runnable, time);
            //将创建的任务放入优先级队列中
            priorityQueue.offer(myTask3);
            //通过notify来唤醒扫描线程
            blocker.notify();
        }
    }

    //内置线程
    public MyTimer3() {
        //创建一个线程
        Thread t = new Thread(() -> {
            //通过while来不断扫描
            while(true) {
                //加锁
                synchronized (blocker) {
                    try {
                        //判断优先级队列是不是空的
                        if(priorityQueue.isEmpty()) {
                            //为空就等待
                            blocker.wait();
                        }
                        //当优先级队列中有任务时,取出任务
                        MyTask3 myTask3 = priorityQueue.peek();
                        //当前时间
                        long time = System.currentTimeMillis();
                        //如果到时间了就执行
                        if(time >= myTask3.getTime()) {
                            myTask3.run();
                            priorityQueue.poll();
                        }else {
                            //时间没到等待 通过wait等待 有时间的等待.
                            blocker.wait(myTask3.getTime() - time);
                        }
                    }catch(InterruptedException o) {
                        o.printStackTrace();
                    }
                }
            }
        });
        //启动线程
        t.start();
    }

specific code

class MyTask3 implements Comparable<MyTask3>{
    //
    private long time;
    private Runnable runnable = null;
    public MyTask3(Runnable runnable, long delay) {
        this.runnable = runnable;
        //需要执行的时刻
        this.time = System.currentTimeMillis() + delay;
    }
    //获取时间
    public long getTime() {
        return time;
    }
    //获取需要执行的代码
    public void run() {
        runnable.run();
    }
    //比较时间快慢方法
    @Override
    public int compareTo(MyTask3 o) {
        return (int)(this.time - o.time);
    }
}

class MyTimer3 {
    //用优先级队列来存放任务
    private PriorityQueue<MyTask3> priorityQueue = new PriorityQueue<>();
    //所对象
    private Object blocker = new Object();
    //核心方法
    public void schedule(Runnable runnable, long time) {
        synchronized (blocker) {
            //创建一个任务
            MyTask3 myTask3 = new MyTask3(runnable, time);
            //将创建的任务放入优先级队列中
            priorityQueue.offer(myTask3);
            //通过notify来唤醒扫描线程
            blocker.notify();
        }
    }

    //内置线程
    public MyTimer3() {
        //创建一个线程
        Thread t = new Thread(() -> {
            //通过while来不断扫描
            while(true) {
                //加锁
                synchronized (blocker) {
                    try {
                        //判断优先级队列是不是空的
                        if(priorityQueue.isEmpty()) {
                            //为空就等待
                            blocker.wait();
                        }
                        //当优先级队列中有任务时,取出任务
                        MyTask3 myTask3 = priorityQueue.peek();
                        //当前时间
                        long time = System.currentTimeMillis();
                        //如果到时间了就执行
                        if(time >= myTask3.getTime()) {
                            myTask3.run();
                            priorityQueue.poll();
                        }else {
                            //时间没到等待 通过wait等待 有时间的等待.
                            blocker.wait(myTask3.getTime() - time);
                        }
                    }catch(InterruptedException o) {
                        o.printStackTrace();
                    }
                }
            }
        });
        //启动线程
        t.start();
    }
}

Code execution flow


Guess you like

Origin blog.csdn.net/paperjie/article/details/134809967