zoukankan      html  css  js  c++  java
  • JAVA多线程提高一:传统线程技术&传统定时器Timer

    前面我们已经对多线程的基础知识有了一定的了解,那么接下来我们将要对多线程进一步深入的学习;但在学习之前我们还是要对传统的技术进行一次回顾,本章我们回顾的则是:传统线程技术和传统的定时器实现.

    一、传统线程技术

    1.创建方式

    1、继承thread类

    Thread t = new Thread(){
        @Override
        public void run() {
        }
    };
    t.start();

    2、实现Runnable接口

    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true) {
            }
        }
    });
    t1.start();

    3、实现Callable接口

    ExecutorService pool = Executors.newCachedThreadPool();
    Future future = pool.submit(new Callable() {
        public Object call() throws Exception {
            return null;
        }
    });

    2.比较

    1、Thread VS Runnable

    • java不支持多继承,允许实现多个接口。Thread是类,Runnable是接口
    • Runnable适合于资源的共享(多个Thread使用相同的Runnable)
    • public class Thread extends Object implements Runnable. Thread是Runnable接口的子类

    2、Runnable VS Callable

    • Callable的 call() 方法可以返回Future类型结果和抛出异常,而Runnable的run()方法没有这些功能
    • Callable通常利用ExecutorService的submit方法去启动call方法,Runnable还可以通过Thread的run方法启动run方法

    二、传统定时器Timer

    1、创建

    到点执行,参数(TimerTask task, Date time),或者(TimerTask task, long delay)延迟多久后执行

    new Timer().schedule(new TimerTask() {
        @Override
        public void run() {
        }
    }, new Date());

    延迟多久执行,然后定时执行,参数(TimerTask task, long delay, long period)或者(TimerTask task, Date firstTime, long period)到点执行,然后定时执行

    new Timer().schedule(new TimerTask() {
        @Override
        public void run() {
        }, 1000, 5000})

    还有类似的scheduleAtFixedRate(TimerTask task, long delay, long period)scheduleAtFixedRate(TimerTask task, Date firstTime,long period)

    2、schedule和scheduleAtFixedRate区别

    • 2个参数的schedule:如果当前时间超过第一次执行时间,则立即执行,否则到定时时间执行
    • 3个参数的schedule:如果当前时间超过第一次执行时间,则立即执行,否则到定时时间执行。下一个任务执行一定是在上一个任务执行完之后执行。下一次任务执行的时间需要看上一个任务执行多久exceTime及周期时间period,如果exceTime>period则立即执行,否则等待period时间再执行。
    • scheduleAtFixedRate:每个任务执行的时间应该是定下了的。如果中间有作业处理时间太长导致后面的不能如期定时执行,则会立即执行后面的作业,直到追上了某一个任务的定时。如果当前时间超过第一次执行时间,则后面所有的作业都会立即执行,直到追上了某一个任务的定时。因为fixed-rate,可能导致同一时间重复执行,所以TimerTask中的执行体需要考虑同步(不是很懂)

    schedule示例:

    new Timer().schedule(new TimerTask(){
        public void run() {  
            try {
                System.out.println("execute task!  "+ dateFormatter.format(this.scheduledExecutionTime()));
                Random random = new Random();
                int slpTime = random.nextInt(3)*1000 + 4000;
                System.out.println("exec time:" + slpTime);
                Thread.sleep(slpTime);
            } catch (InterruptedException e) {
                e.printStackTrace();   
            }  
        }
    },startDate, 5 * 1000);

    输出结果:

    execute task!  2017-12-14 23:26:22 // 当前时间超过了设定了首次执行时间,立即执行
    exec time:1000                     // 第一次执行时间为1s小于周期时间2s
    execute task!  2017-12-14 23:26:24 // 所以第二次在第一次执行时间2s之后执行
    exec time:2000                     // 第三次次执行时间为2s刚好等于周期时间2s
    execute task!  2017-12-14 23:26:26 // 所以第三次在第二次执行时间2s之后执行
    exec time:3000                     // 第三次执行时间为3s大于周期时间2s
    execute task!  2017-12-14 23:26:29 // 所以第四次在第三次执行时间3s之后执行
    exec time:1000                     // 之后就类似
    execute task!  2017-12-14 23:26:31
    exec time:2000
    execute task!  2017-12-14 23:26:33
    exec time:3000
    execute task!  2017-12-14 23:26:36
    exec time:1000
    execute task!  2017-12-14 23:26:38

    scheduleAtFixedRate示例:

    System.out.println("start time: " + dateFormatter.format(new Date()));
    new Timer().scheduleAtFixedRate(new TimerTask(){
        int i = 0;
        int slpTimes[] = new int[] {2000,4000,100,100,100};
        public void run() {
            try {
                System.out.println("execute task:" + i + "!  "+ dateFormatter.format(this.scheduledExecutionTime()) + " now time: " + dateFormatter.format(new Date())) ;
                int slpTime = slpTimes[i++%slpTimes.length];
                System.out.println("exec time:" + slpTime);
                Thread.sleep(slpTime);
            } catch (InterruptedException e) {
                e.printStackTrace();   
            }  
        }
    },startDate, 2 * 1000);

    输出结果:

    start time: 2017-12-15 00:00:09                                     //开始执行时间未到定时
    execute task:0!  2017-12-15 00:01:00 now time: 2017-12-15 00:01:00 //定时开始执行
    exec time:2000                                                      //刚好执行2s
    execute task:1!  2017-12-15 00:01:02 now time: 2017-12-15 00:01:02 //所以第二次在规定时间执行
    exec time:4000                                                      //第二次执行2s,导致第三次延迟执行(第三次应该在2017-12-15 00:01:04执行)
    execute task:2!  2017-12-15 00:01:04 now time: 2017-12-15 00:01:06 //第三次在2017-12-15 00:01:06执行
    exec time:100                                                       //第三次执行100ms
    execute task:3!  2017-12-15 00:01:06 now time: 2017-12-15 00:01:06 //因为之前导致了延迟,需要追赶,所以立即执行,以下类似 
    exec time:100
    execute task:4!  2017-12-15 00:01:08 now time: 2017-12-15 00:01:08
    exec time:100
    execute task:5!  2017-12-15 00:01:10 now time: 2017-12-15 00:01:10
    exec time:2000
    execute task:6!  2017-12-15 00:01:12 now time: 2017-12-15 00:01:12

    3、Timer的缺陷

    Timer的替代品ScheduledExecutorService,这个不在本文进行介绍,后面会进行阐述ScheduledExecutorService.

    参考资料:

    《多线程视频》张孝祥

  • 相关阅读:
    ajax处理响应(三)
    ajax起步 (二)
    ajax的使用(一)
    css相关用法
    vue 实例的生命周期
    vue中computed与watch的异同
    文本显示,单行超出和多行超出显示省略号
    vue+mui+html5+ plus开发的混合应用底部导航的显示与隐藏
    addEventListener()与removeEventListener(),追加事件和删除追加事件
    原生js中获取this与鼠标对象以及vue中默认的鼠标对象参数
  • 原文地址:https://www.cnblogs.com/pony1223/p/9249930.html
Copyright © 2011-2022 走看看