之前讲到Thread的创建,那是Thread生命周期的第一步,其后就是通过start()方法来启动Thread,它会执行一些内部的管理工作然后调用Thread的run()方法,此时该Thread就是alive(活跃)的,而且我们还可以通过isAlive()方法来确定该线程是否启动还是终结。

一旦启动Thread后,我们就只能执行一个方法:run(),而run()方法就是负责执行Thread的任务,所以终结Thread的方法很简单,就是终结run()方法。仔细查看文档,我们会发现里面有一个方法:stop(),似乎可以用来停止Thread,但是这个方法已经被废除了,因为它存在着内部的竞争。

我们经常需要一个不断执行的Thread,然后在某个特定的条件下才会终结它,方法有很多,但最常用的有设定标记和中断Thread两种方式。

我们将之前例子中的Thread改写一下:

public class RandomCharacterGenerator extends Thread implements CharacterSource {
static char[] chars;
static String charArray = "abcdefghijklmnopqrstuvwxyz0123456789";
static {
chars = charArray.toCharArray();
} private volatile boolean done = false; Random random;
CharacterEventHandler handler; public RandomCharacterGenerator() {
random = new Random();
handler = new CharacterEventHandler();
} public int getPauseTime() {
return (int) (Math.max(1000, 5000 * random.nextDouble()));
} @Override
public void addCharacterListener(CharacterListener cl) {
handler.addCharacterListener(cl);
} @Override
public void removeCharacterListener(CharacterListener cl) {
handler.removeCharacterListener(cl);
} @Override
public void nextCharacter() {
handler.fireNewCharacter(this,
(int) chars[random.nextInt(chars.length)]);
} public void run() {
while(!done){
nextCharacter();
try {
Thread.sleep(getPauseTime());
} catch (InterruptedException ie) {
return;
}
}
} public void setDone(){
done = true;
}
}

现在我们多了一个标记:done,这样我们就可以在代码中通过调用setDone()来决定什么时候停止该Thread。这里使用了volatile关键字,它主要是为了同步。这点会放在同步这里讲。
      设定标记的最大问题就是我们必须等待标记的状态,这样就会造成延迟。当然,这种延迟是无法避免的,但必须想办法缩短到最小。于是,中断Thread这种方法就有它的发挥地方了。

我们可以通过interrupt()方法来中断Thread,该方法会造成两个副作用:

1.它会导致任何的阻塞方法都会抛出InterruptedException,我们必须强制性的捕获这个错误哪怕我们根本就不需要处理它,这也是java的异常处理机制让人诟病的一个地方。

2.设定Thread对象内部的标记来指示此Thread已经被中断了,像是这样:

public void run(){
while(!isInterrupted()){
...
}
}

虽然无法避免延迟,但是延迟已经被缩短了。
      无论是采用标记还是中断的方法,我们之所以无法消除延迟的原因是我们无法确定是检查标记先还是调用方法先,这就是所谓的race condition,是线程处理中永远无法避免的话题。

Thread不仅可以被终结,还可以暂停,挂起和恢复。

Thread原本有suspend()方法和resume()方法来执行挂起和恢复,但它们和stop()出于同样的原因,都被废除了。

我们可以通过sleep()方法来挂起Thread,当在指定的时间后,它就会自动恢复。严格意义上讲,sleep并不等同于suspend,真正的suspend应该是由一个线程来挂起另一个线程,但是sleep只会影响当前的Thread。要想真正实现挂起和恢复,我们可以使用等待和通知机制,但这个机制最大的问题就是我们的Thread必须使用该技术来编写。

Thread在终结后,如果有可能,我们还需要对它进行善后。即使Thread已经被终结了,但是其他对象只要还持有它的引用,它们就可以调用该Thread的资源,这也会导致该Thread无法被回收。

但我们有时候还是希望继续保持该Thread的引用,因为我们想要判别它是否真的已经完成了工作,可以使用join()方法。join()方法会被阻塞住直到Thread完成它的run()方法,但是这个存在风险:第一次对join()方法的调用可能会一直被阻塞住很长时间直到Thread真正完成,所以,一般情况下我们还是使用isAlive()方法来判断。

由于我们可以通过实现一个Runnable接口来定义我们的任务,所以在判断所在线程是否已经中断的时候,就有一个问题:该任务还没有绑定到任何线程上。我们可以通过currentThread()方法来获得当前Thread的引用,接着调用isInterrupted()来判断线程是否中断。

一步一步掌握java的线程机制(二)----Thread的生命周期的更多相关文章

  1. java中线程机制

    java中线程机制,一开始我们都用的单线程.现在接触到多线程了. 多线性首先要解决的问题是:创建线程,怎么创建线程的问题: 1.线程的创建: 四种常用的实现方法 1.继承Thread. Thread是 ...

  2. 一步一步掌握java的线程机制(一)----创建线程

    现在将1年前写的有关线程的文章再重新看了一遍,发现过去的自己还是照本宣科,毕竟是刚学java的人,就想将java的精髓之一---线程进制掌握到手,还是有点难度.等到自己已经是编程一年级生了,还是无法将 ...

  3. Java并发1——线程创建、启动、生命周期与线程控制

    内容提要: 线程与进程 为什么要使用多线程/进程?线程与进程的区别?线程对比进程的优势?Java中有多进程吗? 线程的创建与启动 线程的创建有哪几种方式?它们之间有什么区别? 线程的生命周期与线程控制 ...

  4. Java的线程机制

    一.Java中实现多线程的两种方式1) 继承Thread类 Thread类包括了包括和创建线程所需的一切东西. Thread 最重要的方法是 run().编写线程程序时须要覆盖 run() 方法,ru ...

  5. Java精选笔记_多线程(创建、生命周期及状态转换、调度、同步、通信)

    线程概述 在应用程序中,不同的程序块是可以同时运行的,这种多个程序块同时运行的现象被称作并发执行. 多线程可以使程序在同一时间内完成很多操作. 多线程就是指一个应用程序中有多条并发执行的线索,每条线索 ...

  6. 深入浅出 Java Concurrency (30): 线程池 part 3 Executor 生命周期[转]

    我们知道线程是有多种执行状态的,同样管理线程的线程池也有多种状态.JVM会在所有线程(非后台daemon线程)全部终止后才退出,为了节省资源和有效释放资源关闭一个线程池就显得很重要.有时候无法正确的关 ...

  7. JAVA中反射机制二

    声明:如需转载请说明地址来源:http://www.cnblogs.com/pony1223 反射二 利用反射创建对象 1.利用反射创建对象,首先我们创建一个类,类里面,我们知道构造函数有默认的构造函 ...

  8. Android(java)学习笔记171:Service生命周期

    1.Service的生命周期         Android中的Service(服务)与Activity不同,它是不能和用户交互,不能自己启动的,运行在后台的程序,如果我们退出应用的时候,Servic ...

  9. JAVA Eclipse的Android的进程和生命周期是什么

    安卓程序的生命周期是不受自己控制的,安卓的程序根据不同的重要性做了一些区分,最重要的进程仅仅在安卓已经崩溃或者卡死的情况下才会终止前台进程.   Activity就是表现层的界面,它有三种常见的状态, ...

随机推荐

  1. Log4j中conversionPattern的含义

    %a -- 表示礼拜几,英文缩写形式,比如“Fri”%A -- 表示礼拜几,比如“Friday”%b -- 表示几月份,英文缩写形式,比如“Oct”%B -- 表示几月份,“October”%c -- ...

  2. Swift语言精要 - 浅谈结构体(Struct)

    CGRect, CGSize, CGPoint这些是 . String, Int, Array, Dictionary这些我们经常用的也是结构体(Struct). 那么结构体(Struct)到底是什么 ...

  3. HTML DOM 基础知识,成为javascript晋级高手的必备手册

    一.DOM 简介,什么是 DOM? 文件对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展置标语言的标准编程接口. 标记语言,也称置标语言,是一种将文本( ...

  4. Memcached常用命令及使用说明——netcat

    数据存储(假设key为test,value为12345) printf "set test 0 0 5\r\n12345\r\n" | nc 127.0.0.1 12000 STO ...

  5. C#用openfiledialog文件和savefileDialog打开和保存文件

    一 打开文件 Stream myStream = null; OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog ...

  6. 转 VB ListView控件各种操作详解

    Private Sub Form_Load() ListView1.ListItems.Clear '清空列表 ListView1.ColumnHeaders.Clear '清空列表头 ListVie ...

  7. webpack4 css 文件提取 压缩 MiniCssExtractPlugin optimize-css-assets-webpack-plugin

    1.使用的插件 MiniCssExtractPlugin:https://webpack.js.org/plugins/mini-css-extract-plugin/#src/components/ ...

  8. VTK中导入并显示STL、3DS文件

    VTK(visualization toolkit)是一个开源的免费软件系统,主要用于三维计算机图形学.图像处理和科学计算可视化.VTK是在三维函数库OpenGL 的基础上采用面向对象的设计方法发展起 ...

  9. 浅谈Spring的PropertyPlaceholderConfigurer

    大型项目中,我们往往会对我们的系统的配置信息进行统一管理,一般做法是将配置信息配置与一个cfg.properties的文件中,然后在我们系统初始化的时候,系统自动读取cfg.properties配置文 ...

  10. libvlc_new 调用产生段错误

    在调试程序的时候,碰到一个奇怪的段错误问题.只要链接的时候使用-Wl,-rpath=./vlc/lib就会产生段错误,如果链接的时候使用的是-Wl,-rpath=../../tool/vlc/lib则 ...