Java语言导学笔记 Chapter 8 Thread

8.1 什么是线程

def: 线程是程序内的一个单一的顺序控制流程

作为一个顺序的控制流程,线程必须在运行它的程序中占用一些资源。例如,线程必须有它自己的执行堆栈和程序计数器。在线程内运行的代码只在此上下文中工作。其他一些文章将线程称为执行上下文(execution context)。

如果你的程序必须反复执行一个任务,那么应该考虑使用java.util.Timer类。对于在一段程序后执行另一个任务,Timer类也很有用。

如果你正在编写一个具有图形的用户界面(GUI)的程序,那么应该使用javax.swing.Timer类。

对线程的基本支持由java.lang.Thread类提供。它提供了一个线程API并提供了线程的所有共有行为。这些行为包括启动、睡眠、运行、放弃和给予优先级。要使用Thread类实现线程,需要为它提供一个run方法,run方法实际执行线程的任务。

8.2 使用Timer和TimerTask类

Reminder.java这个例子使用计时器在一段延迟时间之后执行一个任务。

import java.util.Timer;

import java.util.TimerTask;

public class Reminder{

Timer timer;

public Reminder(int seconds){

timer = new Timer();

timer.schedule(new RemindTask(), seconds*1000);

}

class RemindTask extends TimerTask{

public void run(){

System.out.println("Time‘s up!");

timer.cancel(); //Terminate the timer thread

}

}

public static void main(String args[]){

new Reminder(5);

System.out.println("Task scheduled.");

}

}

实现和调度有计时器线程执行的任务的基本部分。

1、  实现一个定制的TimerTask子类。run方法包含执行任务的代码。

2、  通过实例化Timer类创建一个线程。

3、  实例化一个计时器任务对象(new RenmindTask())。

4、  调度这个计时器任务的执行。本例使用schedule方法。

让一个任务在特定时间执行:

import java.util.Timer;

import java.util.TimerTask;

import java.util.Calendar;

import java.util.Date;

public class Reminder{

Timer timer;

public Reminder(int seconds){

timer = new Timer();

timer.schedule(new ReminderTask(), seconds*1000);

}

public Reminder(){

Calendar calendar = Calendar.getInstance();

calendar.set(Calendar.HOUR_OF_DAY, 11);

calendar.set(Calendar.MINUTE, 9);

calendar.set(Calendar.SECOND, 0);

Date time = calendar.getTime();

timer = new Timer();

timer.schedule(new RemindTask2(), time);

}

class ReminderTask extends TimerTask{

public void run(){

System.out.println("Time‘s up!");

timer.cancel(); //Terminate the timer thread

}

}

class RemindTask2 extends TimerTask{

public void run(){

System.out.println("Time‘s up! Ring on.");

timer.cancel(); //Terminate the timer thread

}

}

public static void main(String args[]){

new Reminder(5);

new Reminder();

System.out.println("Task scheduled.");

}

}

在默认情况下,只要程序的计时器线程在运行,程序就一直运行。有四种方式可以终止计时器线程。

1、  在计时器线程上调用cancel方法。

2、  使计时器成为“守护线程”(deamon),办法是这样创建计时器: new Timer(true) 。如果程序中仅剩下守护线程,那么程序退出。

3、  在计时器的被调度的所有任务都完成后,删除所有对Timer对象的引用。最后计时器的线程将退出。

4、  调用System.exit方法,使整个程序退出。

重复执行任务:

import java.util.Timer;

import java.util.TimerTask;

import java.awt.Toolkit;

/**

* Schedule a task that executes once every second.

*/

public class AnnoyingBeep {

Toolkit toolkit;

Timer timer;

public AnnoyingBeep() {

toolkit = Toolkit.getDefaultToolkit();

timer = new Timer();

timer.schedule(new RemindTask(),

0,        //initial delay

1*1000);  //subsequent rate

}

class RemindTask extends TimerTask {

int numWarningBeeps = 3;

public void run(){

if (numWarningBeeps > 0) {

toolkit.beep();

System.out.println("Beep!");

numWarningBeeps--;

} else {

toolkit.beep();

System.out.println("Time‘s up!");

//timer.cancel(); //Not necessary because we call System.exit

System.exit(0);   //Stops the AWT thread (and everything else)

}

}

}

public static void main(String args[]) {

System.out.println("About to schedule task.");

new AnnoyingBeep();

System.out.println("Task scheduled.");

}

}

AnnoyingBeep程序使用schedule方法的三参数版本,指定它的任务应该马上开始执行,并且每1秒执行一次。下面是所有可用来调度任务反复执行的方法:

schedule(TimerTask task, long delay, long period)

schedule(TimerTask task, Date time, long period)

scheduleAtFixedRate(TimerTask task, long delay, long period)

scheduleAtFixedRate(TimerTask task, Date firstTime, long period)

在调度任务反复执行时,如果执行的平滑性很重要,那么应该使用schedule方法之一,如果一次蜂鸣声因为某种原因推迟了,那么后续的所有的蜂鸣声将相应延迟;如果时间的同步更重要,那么应该使用scheduleAtFixedRate方法之一,如果想让程序在第一次蜂鸣后正好3秒退出,,如果一次蜂鸣声因为某种原因延迟了,那么两次蜂鸣的时间可能较近,小于1秒。

8.3 定制线程的run方法

有两种技术可以为线程提供run方法:

1、  对Thread类进行子类化并覆盖run方法

2、  实现Runnable接口

对Thread类进行子类化并覆盖run方法

Thread类本身是一个Runnable对象。

public class SimpleThread extends Thread{

public SimpleThread(String str){

super(str);

}

public void run(){

for(int i = 0; i < 10; i++){

System.out.println(i + " " + getName());

try{

sleep((int)(Math.random()*1000));

}catch(InterruptedException e){}

}

System.out.println("Done! " + getName());

}

}

第一个方法是构造器,调用超类构造器设置线程名称。

public class TwoThreadDemo{

public static void main(String[] args){

new SimpleThread("Jamaica").start();

new SimpleThread("Fiji").start();

}

}

实现Runnable接口

import java.awt.Graphics;

import java.util.*;

import java.text.DateFormat;

import java.applet.Applet;

public class Clock extends Applet implements Runnable {

private Thread clockThread = null;

public void start(){

if(clockThread == null){

clockThread = new Thread(this, "Clock");

clockThread.start();

}

}

public void run(){

Thread myThread = Thread.currentThread();

while(clockThread == myThread){

repaint();

try{

Thread.sleep(1000);

}catch(InterruptedException e){

//the VM doesn‘t want us to sleep anymore;

//so get back to work

}

}

}

public void paint(Graphics g){

//get the time and convert it to a date

Calendar cal = Calendar.getInstance();

Date date = cal.getTime();

//format it and display it

DateFormat dateFormatter = DateFormat.getTimeInstance();

g.drawString(dateFormatter.format(date), 5, 10);

}

//overrides Applet‘s stop method, not Thread‘s

public void stop(){

clockThread = null;

}

}

<html>

<head>

<title>Clock</title>

</head>

<body>

I‘m now listening to OuRuoLa

<APPLET CODE= "Clock.class" WIDTH=150 HEIGHT=35></APPLET>

</body>

</html>

这个Clock applet 显示当前时间并且每1秒更新一次。问题是会间接的闪烁,或许和CPU的工作状态有关。用appletviewer Clock.html查看。

Clock applet的run方法进行循环,知道浏览器要求他停止。在循环的每次迭代期间,时钟重新绘制它的显示。

如果你的泪必须子类化另一个类,那么应该使用Runnable接口。

时间: 2024-10-03 13:38:56

Java语言导学笔记 Chapter 8 Thread的相关文章

Java语言导学笔记 Chapter 9 IO

java.io 9.1.1 字符流 Reader为读取器(reader)提供API和部分实现,读取器是读取16位字符的流: Writer为写出器(writer)提供API和部分实现,写出器是写16位字符的流. 一般用来读写文本信息,因为可以处理Unicode字符集中的任何字符,而字节流只能处理ISO-Latin-18位字节?? 9.1.2 字节流 读写8位字节,用InputStream和OutputStream的后代. InputStream和OutputStream为输入流(input str

Java语言导学 (原书第五版)

第一章  快速入门 第二章  面向对象的编程概念 第三章  语言基础    1.continue的用法 第四章  类和对象    1.this关键字  :  2.嵌套类:   3.枚举:   4.注解: 第五章  接口与继承     1.覆盖与屏蔽:   2.super关键字: 第六章  泛型    全章内容看不懂,重点 第七章  程序包   1.命名方式 第八章  数字与字符串   1.StringBuilder类

Java编程思想总结笔记Chapter 3

本章需要总结的不多,但细节的东西需要注意,有些很容易遗忘. 第三章 目录: 3.1 更简单的打印语句 3.2 使用Java操作符 3.3 优先级 3.4 赋值 3.5 算数操作符 3.6 自动递增和递减 3.7 关系操作符 3.8 逻辑操作符 3.9 直接常量 3.10 按位操作符 3.11 移位操作符 3.12 三元操作符 if-else 3.13 字符串操作符 + 和 += 3.14 使用操作符时常犯的错误 3.15 类型转换操作符 3.16 Java没有sizeof 3.17 操作符小结

《C++语言导学》小记

我看的这本是Bjarne Stroustrup写的,南开大学的杨巨峰和王刚译的.这本书不适合初学者看,我就是大概翻了翻其中感兴趣的章节. 这本书第14章的标题是“历史和兼容性”,这节内容我看了收获很深.p144-145的内容值得去看. 从中可以看出,ISO C和ISO C++是K&R C [Kernighan, 1978] 的两个主要后代,因此它们是兄弟.两者发展过程中都从经典C继承了关键特性,但又不都是100%兼容经典C. <C++语言导学>p144 2011年,C++11和C11相

Java编程思想总结笔记Chapter 2

本章介绍Java程序的基本组成部分,体会到Java中几乎一切都是对象. 第二章   一切都是对象 目录: 2.1 用引用操纵对象 2.2 必须由你创建所有对象 2.3 永远不需要销毁对象 2.4 创建新的数据类型:类 2.5 方法.参数和返回值 2.6 构建一个Java程序 2.7 你的第一个Java程序 2.8 注释和嵌入式文档 2.9 编码风格 2.1 用引用操纵对象 一切都看作对象,操纵的标识符实际上是对象的一个"引用",遥控器(引用)操纵电视机(对象),想调控电视,只需通过遥控

Java语言基础学习笔记(七)

烈7A茨谙9m繁5暗MChttp://www.zcool.com.cn/collection/ZMTg3NzE1Njg=.html 3馗iC蓖17握WM啦http://www.zcool.com.cn/collection/ZMTg3NzE2NTI=.html 夜H5P栏k睹19RH评http://www.zcool.com.cn/collection/ZMTg3NzE3MjQ=.html 帐褂61Z仔1D3都瓮1幽Vhttp://www.zcool.com.cn/collection/ZMTg

Java 线程第三版 第八章 Thread与Collection Class 读书笔记

JDK1.2引入最有争议性的改变是将集合类默认为不是Thread安全性的. 一.Collection Class的概述 1. 具有Threadsafe 的Collection Class: java.util.Vector(List) 列表集合,通过索引操作. java.util.Stack(List) 继承自Vector,提供LIFO的顺序操作push进入,pop出元素. java.util.Hashtable(Map) 一个简单.无序的key与value的映射. java.util.conc

Java 线程第三版 第一章Thread导论、 第二章Thread的创建与管理读书笔记

第一章 Thread导论 为何要用Thread ? 非阻塞I/O I/O多路技术 轮询(polling) 信号 警告(Alarm)和定时器(Timer) 独立的任务(Task) 并行算法 第二章 Thread的创建与管理 一.什么是Thread ? Thread是所在主机执行的应用程序任务(task). 只有一个线程的例子: public class Factorial { public static void main(String[] args) { int n = 5; System.ou

C#&amp;java重学笔记(函数)

C#部分  1.写在函数定义的()中的关键字: a.params关键字:用来满足函数的参数为数组时,而数组的长度不固定的情况.且该关键字只能用来修饰数组型参数.这样一修饰,就达成了类似JavaScript函数书写参数的特点. b.ref关键字:让参数按引用传递,类似于C中的传指针参数.比如经典的数值交换函数,你传形参和传指针的结果应该知道,加了ref关键字就相当于传指针.注意:ref只接收变量做参数,你字面量怎么弄指针?而且该变量必须初始化!     c.out关键字:功能和ref一样,区别在于