• Timer与TimerTask之二:timer使用缺陷及用ScheduledThreadPoolExecutor解决


    1.缺陷一:Timer由于内部只要一个线程,管理多个任务的时候,一个任务延时,后面的任务就会跟着延时。用下面的例子说明:

    package com.dxz.timer;
    
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class TimerTaskTest {
        private static long startTime;
    
        public static void main(String[] args) {
    
            // 创建一个定时task1
            TimerTask task1 = new TimerTask() {
    
                @Override
                public void run() {
                    System.out.println("task1 excude ..." + (System.currentTimeMillis() - startTime));
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            // 创建一个定时task2
            TimerTask task2 = new TimerTask() {
    
                @Override
                public void run() {
                    System.out.println("task2 excude ..." + (System.currentTimeMillis() - startTime));
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
    
            Timer timer = new Timer("TimerThread");
            startTime = System.currentTimeMillis();
            // 第1个任务1s后,执行
            timer.schedule(task1, 1000);
            // 第2个任务3s后,执行
            timer.schedule(task2, 3000);
    
        }
    
    }

    结果:

    task1 excude ...1001
    task2 excude ...4002

    从上面的代码看出,第一个任务1s后执行,第二个任务3s后执行。实际上task2是在4s后才执行的,因为Timer内部是一个线程,而task1所需的时间超过了两个任务的间隔时间导致。下面使用ScheduledThreadPool解决上面的问题:

    package com.dxz.timer;
    
    import java.util.TimerTask;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    
    public class ScheduledThreadPoolTest1 {
    
        private static long startTime;
    
        public static void main(String[] args) {
            ScheduledExecutorService newExecutorService = Executors.newScheduledThreadPool(2);
    
            // 创建一个定时task1
            TimerTask task1 = new TimerTask() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + " excude ..."
                            + (System.currentTimeMillis() - startTime) + "ms");
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            // 创建一个定时task2
            TimerTask task2 = new TimerTask() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + " excude ..."
                            + (System.currentTimeMillis() - startTime) + "ms");
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
    
            startTime = System.currentTimeMillis();
            // 第1个任务1000 表示1s后,执行
            newExecutorService.schedule(task1, 1000, TimeUnit.MILLISECONDS);
            // 第2个任务3000 表示3s后,执行
            newExecutorService.schedule(task2, 3000, TimeUnit.MILLISECONDS);
    
        }
    
    }

    结果:

    pool-1-thread-1 excude ...1001ms
    pool-1-thread-2 excude ...3002ms

    2、缺陷二:

    package com.dxz.timer;
    
    import java.util.Date;
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class TimerTaskTest2 {
        private static long startTime;
    
        public static void main(String[] args) {
            // 创建一个定时task1
            TimerTask task1 = new TimerTask() {
                @Override
                public void run() {
                    throw new RuntimeException("运行时异常");
                }
            };
            // 创建一个定时task2
            TimerTask task2 = new TimerTask() {
                @Override
                public void run() {
                    System.out.println("task2 excude ..." + (System.currentTimeMillis() - startTime));
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
    
            Timer timer = new Timer("TimerThread");
            startTime = System.currentTimeMillis();
            timer.schedule(task1, 100);
            timer.scheduleAtFixedRate(task2, new Date(), 1000);
    
        }
    
    }

    结果:

    task2 excude ...2
    Exception in thread "TimerThread" java.lang.RuntimeException: 运行时异常
        at com.dxz.timer.TimerTaskTest2$1.run(TimerTaskTest2.java:15)
        at java.util.TimerThread.mainLoop(Timer.java:555)
        at java.util.TimerThread.run(Timer.java:505)

    使用ScheduledExecutorService来解决:

    package com.dxz.timer;
    import java.util.TimerTask;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    
    public class ScheduledThreadPoolTest2 {
    
        private static long startTime;
    
        public static void main(String[] args) {
            ScheduledExecutorService newExecutorService = Executors.newScheduledThreadPool(1);
    
            // 创建一个定时task1
            TimerTask task1 = new TimerTask() {
                @Override
                public void run() {
                    new RuntimeException();
                }
            };
            // 创建一个定时task2
            TimerTask task2 = new TimerTask() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + " excude ..." + (System.currentTimeMillis() - startTime) + "ms");
                }
            };
    
            startTime = System.currentTimeMillis();
            newExecutorService.schedule(task1, 0, TimeUnit.MILLISECONDS);
            // 第2个任务3000 表示3s后,执行
            newExecutorService.scheduleAtFixedRate(task2,1000, 1000, TimeUnit.MILLISECONDS);
    
        }
    
    }

    结果:

    pool-1-thread-1 excude ...1002ms
    pool-1-thread-1 excude ...2001ms
    pool-1-thread-1 excude ...3002ms
    pool-1-thread-1 excude ...4002ms
  • 相关阅读:
    C# 各种数据类型的最大值和最小值常数
    使用EntityFramework6连接MySql数据库(db first方式)
    apache ignite系列(八):问题汇总
    apache ignite系列(六): 服务网格
    golang实现get和post请求的服务端和客户端
    python+selenium调用chrome打开网址获取内容
    spring-boot集成spark并使用spark-sql
    apache ignite系列(五):分布式计算
    sqoop导oracle数据到hive中并动态分区
    python使用cx_Oracle连接oracle
  • 原文地址:https://www.cnblogs.com/duanxz/p/2769616.html
Copyright © 2020-2023  润新知