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.

参考资料:

《多线程视频》张孝祥

原文地址:https://www.cnblogs.com/pony1223/p/9249930.html

时间: 2024-10-19 23:23:24

JAVA多线程提高一:传统线程技术&传统定时器Timer的相关文章

JAVA多线程提高三:线程范围内共享变量&ThreadLocal

今天我们学习的是如何在线程自己的范围内达到变量数据的共享,而各个线程之间又是互相独立开来,各自维护的,即我们说的ThreadLocal的作用. 一.概念 可以将每个线程用到的数据与对应的线程号存放到一个map集合中,使用数据时从这个集合中根据线程号获取对应线程的数据,就可以实现线程范围内共享相同的变量. 二.代码 Runnable中的run()方法里面执行Thread.currentThread()都会对应当前Runnable对应的线程,因此A.B中对应的Thread.currentThread

Java 传统线程技术

Java 多线程 在Java中,线程类Thread创建方式有两种:一是继承Thread类,重写run方法:二是,实现Runnable接口.大多数情况下,推荐使用第二种方式,实现runnable接口,这样可以很好的将任务与执行单元分离,更加突出面向对象的思想. 在JDK1.5之前,线程间互斥主依靠内置锁(监视器),而线程间通信则采用Object实例的wait,notify等方法.在JDK1.5之后,增加了很多线程新技术,如线程池.锁.信号量.条件.栅栏.阻塞队列.同步容器等. 1.       传

【java并发】传统线程技术中的定时器技术

传统线程技术中有个定时器,定时器的类是Timer,我们使用定时器的目的就是给它安排任务,让它在指定的时间完成任务.所以先来看一下Timer类中的方法(主要看常用的TimerTask()方法): 返回值 方法名 方法描述 void schedule(TimerTask task, long delay) 安排在指定延迟后执行指定的任务. void schedule(TimerTask task, long delay, long period) 安排指定的任务从指定的延迟后开始进行重复的固定延迟执

传统线程技术回顾

/** * * @描述: 传统线程技术回顾 . * <p> * *   多线程机制会提高程序的运行效率? * ============================================== 不会,会更慢,因为CPU资源有限 为什么会有多线程下载呢? 是为了抢夺服务器带宽 ============================================== 不一定,多线程又不能提高CPU的主频,也就是单位时间能够执行的指令数目,如果是一个单线程的任务, CPU也只能处理单线

Java多线程-同步:synchronized 和线程通信:生产者消费者模式

大家伙周末愉快,小乐又来给大家献上技术大餐.上次是说到了Java多线程的创建和状态|乐字节,接下来,我们再来接着说Java多线程-同步:synchronized 和线程通信:生产者消费者模式. 一.同步:synchronized 多个线程同时访问一个对象,可能造成非线程安全,数据可能错误,所谓同步:就是控制多个线程同时访就是控制多线程操作同一个对象时,注意是同一个对象,数据的准确性, 确保数据安全,但是加入同步后因为需要等待,所以效率相对低下. 如:一个苹果,自己一个人去咬怎么都不会出问题,但是

Java 多线程(三) 线程的生命周期及优先级

Java 多线程(三) 线程的生命周期及优先级 线程的生命周期 线程的生命周期:一个线程从创建到消亡的过程. 如下图,表示线程生命周期中的各个状态: 线程的生命周期可以分为四个状态: 1.创建状态: 当用new操作符创建一个新的线程对象时,该线程处于创建状态. 处于创建状态的线程只是一个空的线程对象,系统不为它分配资源. 2.可运行状态: 执行线程的start()方法将为线程分配必须的系统资源,安排其运行,并调用线程体——run()方法,这样就使得该线程处于可运行状态(Runnable). 这一

Java多线程编程基础之线程对象

在进入java平台的线程对象之前,基于基础篇(一)的一些问题,我先插入两个基本概念. [线程的并发与并行] 在单CPU系统中,系统调度在某一时刻只能让一个线程运行,虽然这种调试机制有多种形式(大多数是时间片轮巡为主),但无论如何,要通过不断切换需要运行的线程让其运行的方式就叫并发(concurrent).而在多CPU系统中,可以让两个以上的线程同时运行,这种可以同时让两个以上线程同时运行的方式叫做并行(parallel). 在上面包括以后的所有论述中,请各位朋友谅解,我无法用最准确的词语来定义储

Java多线程之简单的线程同步实例

数据类: package Thread.MyCommon; public class Data { public int num = 0; public synchronized int getEven() { ++num; Thread.yield();//让另外线程先执行,加大测试效果几率 ++num; return num; } } 线程类: package Thread.MyCommon; public class myThread implements Runnable { priva

Java多线程之 -- 进程和线程

Java多线程之 – 进程和线程 概念 进程 程序的动态执行过程 包括占用的资源(内存.CPU)和线程 线程 线程是程序中最小的执行单位 一个进程有多个线程 线程共享进程的资源 进程和线程的区分 我们可以想象为进程为班级而线程是邦奇中得每一个学生 线程之间的交互 互斥,类似于每一个学生都为了第一名而你争我让,线程也是,都想抢占CPU的资源 同步,当举行运动会的时候,大家都团结一心,彼此共享自己的资源 Thread.Runnable Thread Introduction Thread 是Java