一步一步掌握java的线程机制(二)----Thread的生命周期
之前讲到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的生命周期的更多相关文章
- java中线程机制
java中线程机制,一开始我们都用的单线程.现在接触到多线程了. 多线性首先要解决的问题是:创建线程,怎么创建线程的问题: 1.线程的创建: 四种常用的实现方法 1.继承Thread. Thread是 ...
- 一步一步掌握java的线程机制(一)----创建线程
现在将1年前写的有关线程的文章再重新看了一遍,发现过去的自己还是照本宣科,毕竟是刚学java的人,就想将java的精髓之一---线程进制掌握到手,还是有点难度.等到自己已经是编程一年级生了,还是无法将 ...
- Java并发1——线程创建、启动、生命周期与线程控制
内容提要: 线程与进程 为什么要使用多线程/进程?线程与进程的区别?线程对比进程的优势?Java中有多进程吗? 线程的创建与启动 线程的创建有哪几种方式?它们之间有什么区别? 线程的生命周期与线程控制 ...
- Java的线程机制
一.Java中实现多线程的两种方式1) 继承Thread类 Thread类包括了包括和创建线程所需的一切东西. Thread 最重要的方法是 run().编写线程程序时须要覆盖 run() 方法,ru ...
- Java精选笔记_多线程(创建、生命周期及状态转换、调度、同步、通信)
线程概述 在应用程序中,不同的程序块是可以同时运行的,这种多个程序块同时运行的现象被称作并发执行. 多线程可以使程序在同一时间内完成很多操作. 多线程就是指一个应用程序中有多条并发执行的线索,每条线索 ...
- 深入浅出 Java Concurrency (30): 线程池 part 3 Executor 生命周期[转]
我们知道线程是有多种执行状态的,同样管理线程的线程池也有多种状态.JVM会在所有线程(非后台daemon线程)全部终止后才退出,为了节省资源和有效释放资源关闭一个线程池就显得很重要.有时候无法正确的关 ...
- JAVA中反射机制二
声明:如需转载请说明地址来源:http://www.cnblogs.com/pony1223 反射二 利用反射创建对象 1.利用反射创建对象,首先我们创建一个类,类里面,我们知道构造函数有默认的构造函 ...
- Android(java)学习笔记171:Service生命周期
1.Service的生命周期 Android中的Service(服务)与Activity不同,它是不能和用户交互,不能自己启动的,运行在后台的程序,如果我们退出应用的时候,Servic ...
- JAVA Eclipse的Android的进程和生命周期是什么
安卓程序的生命周期是不受自己控制的,安卓的程序根据不同的重要性做了一些区分,最重要的进程仅仅在安卓已经崩溃或者卡死的情况下才会终止前台进程. Activity就是表现层的界面,它有三种常见的状态, ...
随机推荐
- 【Python】使用geopy由经纬度找地理信息
from geopy.geocoders import Nominatim geolocator = Nominatim() location = geolocator.reverse("3 ...
- iOS编程(双语版) - 视图 - 手工代码(不使用向导)创建视图
如何创建一个空的项目,最早的时候XCode的项目想到中,还有Empty Application template这个选项,后来Apple把它 给去掉了. 我们创建一个单视图项目. 1) 删除main. ...
- 更新image的方法
1. 修改container 1.1 执行 docker images 查看目前的所有images: REPOSITORY TAG IMAGE ID ...
- Django模板过滤器详解
Django 模板过滤器也是我们在以后基于 Django 网站开发过程中会经常遇到的,如显示格式的转换.判断处理等.以下是 Django 过滤器列表,希望对为大家的开发带来一些方便. 一.形式:小写 ...
- hadoop 文件合并
来自:http://blog.csdn.net/dandingyy/article/details/7490046 众所周知,Hadoop对处理单个大文件比处理多个小文件更有效率,另外单个文件也非常占 ...
- Python2.7.14新手学习
python2.7.14 让用户选择一个功能,然后对其进行操作的例子.中间有问题的是年龄没有做是否是数字判断 注意:和版本python3不同的地方 1.编码 2.输入地方是raw_input 3.业务 ...
- Java中的List
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6538256.html Java中常用的List子类主要有:ArrayList.LinkedList.Vecto ...
- eclipse debug模式下总是自动跳到ThreadPoolExecutor.java类
1.情景展示 使用eclipse,debug模式运行项目时,总是会调用这个ThreadPoolExecutor.java类,明明没有打断点却自动停止运行. 2.原因分析 在eclipse中,默认是 ...
- Knockoutjs之observable和applyBindings的使用
observable在Knockoutjs中属于一个核心功能,在做监控数据的改变时,必须要用到Knockoutjs的监控属性——observable. ko.observable()的简单使用 首先来 ...
- tablib.Dataset()操作exl类型数据之“类方法”研究
#tablib.Dataset()操作exl类型数据之“类方法”研究 import tablib #初始化 data=tablib.Dataset() #设置列标题 data.headers=('na ...