`
足至迹留
  • 浏览: 485367 次
  • 性别: Icon_minigender_1
  • 来自: OnePiece
社区版块
存档分类
最新评论

<基础-3> 线程状态及属性

阅读更多
1.线程状态
线程有如下6种枚举状态:
1)New新生态,2)Runnable 可运行态,3)Blocked被阻塞态 4)Waiting等待态 5)Timed waiting计时等待态 6)Terminated被终止态。
要确定一个线程的当前状态,可以调用Thread的实例方法getState()方法,返回State枚举对象

1.1 新生线程
当用new操作符创建一个新线程时,如new Thread(r), 该线程还没有开始运行。这意味着它的状态时new。此时程序还没开始运行线程中的代码。

1.2 可运行线程
一旦调用start()方法,线程处于runnable状态。一个“可运行”的线程可能正在运行也可能没有运行,这取决于操作系统给线程提供运行的时间。

1.3 被阻塞线程和等待线程和计时等待线程
当线程处在阻塞或等待状态时,它暂时不活动。它不运行任何代码且消耗最少的资源。直到线程调度器重新激活它。

1) 当一个线程试图获取一个内部的对象锁(而不是java.util.concurrent库中的锁),而该锁被其他线程持有,则该线程进入阻塞状态。当所有其他线程释放该锁,并且线程调度允许本线程持有它的时候,该线程将变成非阻塞状态。

2) 当线程等待另一个线程通知调度器一个条件时,它自己进入等待状态。在调用Object.wait方法或Tread.join方法,或等待java.util.concurrent库中的Lock或Condition时,就会出现这种情况。实际上,被阻塞状态和等待状态是有很大不同的。简而言之:等待是等待cpu,阻塞是等待锁。

3) 有几个方法有一个超时参数,调用他们导致线程进入计时等待(timed waiting)状态。这一状态将一直保持到超时期满或接收到适当的通知,带有超时参数的方法有Thread.sleep和Object.wait,Thread.join, Lock.tryLock以及Condition.await的计时版。

Java的线程状态转换图:



1.4 被终止的线程
线程因如下三个原因终止:
1) 因为run方法正常退出而自然死亡。
2) 因为一个没有捕获的异常终止了run方法而意外死亡。
3) 调用interrupt方法。

特别是,可以调用线程Thread的stop方法杀死一个线程,该方法抛出ThreadDeath错误对象,由此杀死线程。但是,stop方法已过时,不要在自己的代码中使用它(类似stop,还有suspend,resume方法也已经过时,后面会说明stop和suspend为何废弃)。

2. 中断线程
当线程的run方法执行完毕并经由执行return语句返回时,或出现了在方法中没有捕获的异常时,线程将终止。
在早起版本,Thread有一个stop方法,其他线程可以调用它终止线程,但现在已废弃了。

有一种可强制终止线程的方法,Thread的interrupt()方法,可以用来请求os终止线程(并不是立即终止)。当对一个线程调用interrupt()方法时,线程的中断状态将被置位。这是每一个线程都具有的boolean标志。可以调用Thread.currentThread.isInterrupted()判断当前线程是否中断。

但是,如果线程被阻塞(比如已经调用过了sleep()或wait()方法),就无法检测中断状态。这是产生InterruptedException的地方。阻塞库(比如Thread.sleep, Object.wait)方法都会自己检测线程何时中断,并且发现中断就提前返回,他们响应中断的操作为:清除中断标志+抛出InterruptedException
当在一个被阻塞的线程上调用interrupt()方法时,阻塞调用将会被InterruptedException中断(存在不能被中断的阻塞I/O调用,应该考虑选择可中断的调用)。也就是当同一个线程在sleep(或其他阻塞状态)状态时调用interrupt方法就会导致sleep终止,并抛出InterruptedException异常,同样如果一个线程在isInterrupedException返回true状态时调用sleep(或其他阻塞状态)时也会InterruptedException异常。

一般来说,阻塞函数,如:Thread.sleep、Thread.join、Object.wait、LockSupport.park等在检查到线程的中断状态时,会抛出InterruptedException,同时会清除线程的中断状态.

对中断的正确理解是:它不会立即中断正在执行的线程,而只是发出中断请求,然后由线程在下一个合适的时刻中断自己。

2.1 响应中断
通常有两种实用策略来响应中断:
1)传递异常(可能在执行某个特定于任务的清除操作之后),从而使你的方法也成为可中断的阻塞方法;
2)恢复中断状态,从而使调用栈中的上层代码能对异常进行处理。如下面示例2那样处理,Thread.currentThread().interrupt();



示例1:
public class InterruptedTest implements Runnable
{
    @Override
	public void run() 
	{
		while(true)
		{
			try
			{
				System.out.println("Thread sleep()");
				Thread.sleep(5000);
			}
			catch (InterruptedException e)
			{
				System.out.println("Thread interrupedException, and Thread.currentThread().isInterrupted() = " + Thread.currentThread().isInterrupted());
			}
		}
	}
    
    public static void main(String[] args)
    {
    	InterruptedTest run = new InterruptedTest();
    	Thread thread = new Thread(run);
    	
// 启动线程进入sleep状态。
    	thread.start();
    	
    // 立刻中断线程。
    	thread.interrupt();
    }
}
Main 方法输出:
Thread sleep()
Thread interrupedException, and Thread.currentThread().isInterrupted() = false
Thread sleep()
Thread sleep()
Thread sleep()
…


小示例2:
{
    @Override
	public void run() 
	{
		while(true)
		{
			try
			{
				System.out.println("Thread sleep()");
				Thread.sleep(2000);
			}
			catch (InterruptedException e)
			{
				System.out.println("Thread interrupedException, and Thread.currentThread().isInterrupted() = " + Thread.currentThread().isInterrupted());
				Thread.currentThread().interrupt();
				System.out.println("Thread interrupedException, and Thread.currentThread().isInterrupted() = " + Thread.currentThread().isInterrupted());
			}
		}
	}
    
    public static void main(String[] args)
    {
    	InterruptedTest run = new InterruptedTest();
    	Thread thread = new Thread(run);
    	
     // 启动线程
    	thread.start();
    	
    	// 中断线程触发中断异常,在异常里设置中断状态,导致每次调sleep时都异常。
    	thread.interrupt();
    }
}
Main方法输出:
Thread sleep()
Thread interrupedException, and Thread.currentThread().isInterrupted() = false
Thread interrupedException, and Thread.currentThread().isInterrupted() = true
Thread sleep()
Thread interrupedException, and Thread.currentThread().isInterrupted() = false
Thread interrupedException, and Thread.currentThread().isInterrupted() = true
Thread sleep()
Thread interrupedException, and Thread.currentThread().isInterrupted() = false
Thread interrupedException, and Thread.currentThread().isInterrupted() = true
Thread sleep()
…


通常捕获到中断异常后会设置中断状态或抛出异常处理不要忽略异常
对于InterruptedException的处理,可以有两种情况:
(1)外层代码可以处理这个异常,直接抛出这个异常即可
(2)如果不能抛出这个异常,比如在run()方法内,因为在得到这个异常的同时,线程的中断状态已经被清除了,需要保留线程的中断状态,则需要调用Thread.currentThread().interrupt()

没有任何语言方面的需求要求一个被中断的线程应该终止,中断一个线程不过是引起它的注意,被中断的线程可以决定如何响应中断。
如果在每次工作迭代之后都调用sleep方法(或其他可中断的方法),isInterrupted检测既没有必要也没有用处。因为,如果在中断状态被置位时调用sleep方法,它不会休眠而是清除这一状态并抛出InterruptedException。

有两个非常类似的方法,interrupted()和isInterrupted()。
1)Interrupted方法是一个静态方法,它既可以得到上一次线程的中断标志值,又可以同时清除线程的中断标志,一举两得,但同时也有坏处,就是这个函数有清除中断状态的副作用.
2)isInterrupted方法是一个实例方法,可用来检测线程是否被中断,调用这个方法不会改变中断状态。

3. 为什么弃用stop和suspend
Stop方法天生就不安全经验证明suspend方法会经常导致死锁

首先看stop方法,该方法终止所有未结束的方法,包括run方法。当线程被终止,立即释放被它锁住的所有对象的。这会导致对象处于不一致的状态。例如转账功能,当从一个账户已经扣款而没有存入另一个账户时线程终止。这样银行对象就被破坏了,因为锁已经被释放,这种破坏会被其他尚未停止的线程观察到。
当线程要终止另一个线程时,无法知道什么时候调用stop方法是安全的,什么时候导致对象被破坏,因此,该方法被弃用了。取而代之,在希望停止线程的时候应该中断线程(interrupt),被中断的线程会在安全的时候停止

与stop不同,suspend不会破坏对象。但是,如果用suspend挂起一个持有一个锁的线程,那么该锁在恢复之前是不可用的。如果调用suspend方法的线程视图获得同一个锁,那么程序死锁,被挂起的线程等着被回复,而将其挂起的线程等待获得锁。同样Object的sleep也不会释放锁。推荐使用Object的wait或Condition的await,这两者阻塞的时候都会释放占有的锁。

4. 线程属性
下面将讨论线程的各种属性,其中包括:线程优先级,守护线程,线程组以及处理未捕获异常的处理器。

4.1 线程优先级
在java程序中,每一个线程都有一个优先级。默认情况下,一个线程继承它的父线程的优先级。可以用setPriority方法提高或降低任何一个线程的优先级。可以将线程优先级设置为MIN_PRIORITY(Thread类中定义为1)与MAX_PRIORITY(定义为10)之间的任何值。NORM_PRIORITY被定义为5.
每当线程调度器有机会选择新线程时,它首先选择具有较高优先级的线程。但是,线程优先级高度依赖于系统。当虚拟机依赖于宿主平台的线程实现机制时,java线程的优先级被映射到宿主平台的优先级上,优先级个数也许更多,也许更少。
初级程序员常常过度使用线程优先级,不要将程序构建为功能的正确性依赖于优先级。

4.2 守护线程
可以通过调用t.setDaemon(true)将线程转换为守护线程(daemon thread)。守护线程的唯一用途是为其他线程提供服务。计时线程就是一个例子。
当只剩下守护线程时,虚拟机就退出了。

4.3 未捕获异常处理器
线程的run方法不能抛出任何被检测的异常(也就是run方法签名不能有throws关键字抛出任何非RuntimeException),但是,不被检测的异常会导致线程终止。在这种情况下,线程就死亡了。也就是:run方法只能抛出运行时异常RuntimeException

但是,不需要任何catch子句来处理可以被传播的异常(当一个异常被抛出以后,程序将控制权转移给try语句中第一个能够处理该异常的catch子句。这个从异常抛出到控制转移给合适的异常处理语句的过程就叫做异常传播)。相反,就在线程死亡之前,异常被传递到一个用于未捕获异常的处理器。这个处理器必须属于一个实现Thread.UncaughtExceptionHandle接口的类。这个接口只有一个方法:
Void uncaughtException(Thread t, Throwable e)

从jdk5.0起,可以用setUncaughtExceptionHandler方法为任何线程安装一个处理器。也可以用Thread类的静态方法setDefaultUncaughtExceptionHandler为所有线程安装一个默认的处理器。如果不安装默认的处理器,默认的处理器就为空。但是,如果不为独立的线程安装处理器,此时的处理器就是该线程的ThreadGroup对象。

ThreadGroup类实现Thread.UncaughtExceptionHandler接口。它的uncaughtException方法做如下操作:
1) 如果该线程组有父线程组,那么父线程组的uncaughtException方法被调用。
2) 否则,如果Thread.getDefaultExceptionHandler方法返回一个非空的处理器,则调用该处理器。
3) 否则,如果Throwable是ThreadDeath的一个实例,什么都不做(ThreadDeath对象由stop方法产生,而该方法已经过时)。
4) 否则,线程的名字以及Throwable的栈踪迹被输出到System.err上。


  • 大小: 137.5 KB
0
0
分享到:
评论
1 楼 timer_yin 2014-02-08  
学习了 mark

相关推荐

    C#编程经验技巧宝典

    2&lt;br&gt;&lt;br&gt;0003 设置程序代码行序号 3&lt;br&gt;&lt;br&gt;0004 开发环境全屏显示 3&lt;br&gt;&lt;br&gt;0005 设置窗口的自动隐藏功能 3&lt;br&gt;&lt;br&gt;0006 根据需要创建所需解决方案 4&lt;br&gt;&lt;br&gt;0007 如何使用“验证的目标架构”功能 4&lt;br&gt;...

    java面试800题

    &lt;type-version&gt;7.0&lt;/type-version&gt; &lt;type-storage&gt;META-INF/weblogic-cmp-rdbms-jar.xml&lt;/type-storage&gt; &lt;/persistence-use&gt; &lt;/persistence&gt; &lt;/entity-descriptor&gt; &lt;jndi-name&gt;com.ejb.CatalogHome&lt;/jndi-name...

    C#源码大集合 01(共3卷)

    多接收模式串口类&lt;br&gt;├─实例10-多线程实例&lt;br&gt;├─实例12-多线程互斥1&lt;br&gt;├─实例13-多线程互斥2&lt;br&gt;├─实例14-多线程互斥3&lt;br&gt;├─实例63 如何编写多线程程序&lt;br&gt;├─实例77-多线程1&lt;br&gt;├─实例78-多...

    C#源码大集合 03(共3卷)

    多接收模式串口类&lt;br&gt;├─实例10-多线程实例&lt;br&gt;├─实例12-多线程互斥1&lt;br&gt;├─实例13-多线程互斥2&lt;br&gt;├─实例14-多线程互斥3&lt;br&gt;├─实例63 如何编写多线程程序&lt;br&gt;├─实例77-多线程1&lt;br&gt;├─实例78-多...

    程序设计基础答案

    &lt;br&gt;A) 6 B) 9 C) 11 D) 3&lt;br&gt;20.对于一个三位的正整数 n,取出它的十位数字k(k为整型)的表达式是( )。&lt;br&gt;A) k = n / 10 % 10 B) k = ( n - n / 100 * 100 )%10&lt;br&gt;C) k = n % 10 D) k = n / 10&lt;br&gt;21.现有一变量...

    mysql5.1中文手册

    复制从I/O线程状态&lt;br&gt;6.3.3. 复制从SQL线程状态&lt;br&gt;6.3.4. 复制传递和状态文件&lt;br&gt;6.4. 如何设置复制&lt;br&gt;6.5. 不同MySQL版本之间的复制兼容性&lt;br&gt;6.6. 升级复制设置&lt;br&gt;6.6.1. 将复制升级到5.0版&lt;br&gt;6.7. 复制特性...

    线程属性理解源码——属性、释放线程

    这是一个很简单的线程项目,主要是跟踪了线程各个阶段的属性的状态,还有如何释放一个线程,很基础,下载请慎重!

    新版Android开发教程.rar

    ----------------------------------- Android 编程基础 1 封面----------------------------------- Android 编程基础 2 开放手机联盟 --Open --Open --Open --Open Handset Handset Handset Handset Alliance ...

    linux多线程编程

    第一章 线程基础知识 2 一.什么是线程 2 二.线程的优点 2 三.线程的缺点 2 四.线程的结构 2 五.线程标识 2 六.线程的创建 3 七..线程的终止 4 八、一次性初始化 8 九、线程的私有数据 9 第二章 线程高级知识 ...

    (重要)AIX command 使用总结.txt

    S State -&gt;列出指定状态的设备,3种状态可选,(1)已定义-&gt;defined,d,D,0;(2)可用-&gt;available,a,A,1;(3)停止-&gt;stopped,s,S,2; s Subclass -&gt;指定设备的子类名称,subclass包括什么类型可用参数P显示; t Type -&gt;指定...

    从J2SE到J2EE知识点介绍

    3. 生命周期及状态转换 84 4. 线程调度 85 5. 线程同步 92 三. Jsp 101 (一) myeclipse上配置Tomcat服务器 101 (二) Jsp+servlet+bean版HelloWorld概览 105 (三) Jsp基本页面标签 116 1. &lt;@ page %&gt;标签 116 2. ...

    易语言程序免安装版下载

    ** 以下是易语言4.x及以前版本的升级信息 ******************************************************************************** 易语言4.14版相对于4.13更新说明: 对易语言核心支持库、编译器、开发环境的更新...

    Delphi多线程编程之三 同步读写全局数据

    if Lock&lt;&gt;3 then //非互斥情况 begin if Lock=2 then EnterCriticalSection(CS); //建立临界区 for i := 1 to MaxSize do begin GlobalArry[i]:=GetNextNumber; Sleep(5); end; if Lock=2 then ...

    linux系统下多线程编程文档资料

    第一章 线程基础知识 2 一.什么是线程 2 二.线程的优点 2 三.线程的缺点 2 四.线程的结构 2 五.线程标识 2 六.线程的创建 3 七..线程的终止 4 八、一次性初始化 8 九、线程的私有数据 9 第二章 线程高级知识 ...

    java 基础教程之多线程详解及简单实例

    主要介绍了java 基础教程之多线程详解及简单实例的相关资料,线程的基本属性、如何创建线程、线程的状态切换以及线程通信,需要的朋友可以参考下

    C#微软培训资料

    &lt;&lt;page 3&gt;&gt; page begin==================== 14.2 多 态 性 .159 14.3 抽象与密封 .163 14.4 继承中关于属性的一些问题.169 14.5 小 结 .172 第四部分 深入了解 C#.174 第十五章 接 口 .174 15.1 组件...

    Java语言基础下载

    线程状态和调度 ….176 线程中断/恢复的几种方式 178 创建线程的两种方式 179 线程的控制 180 实例分析 182 内容总结 189 独立实践 190 第十二章:高级I/O流 192 学习目标 192 I/O基础知识 193 字节流 193 字符流 ...

    在同步代码结束后,使用ReleaseMutex(THandle

    if Lock&lt;&gt;3 then //非互斥情况 begin if Lock=2 then EnterCriticalSection(CS); //建立临界区 for i := 1 to MaxSize do begin GlobalArry[i]:=GetNextNumber; Sleep(5); end; if Lock=2 then ...

    多线程编程指南PDF

    多线程基础介绍.........................................................................................................................................15 定义多线程术语...................................

Global site tag (gtag.js) - Google Analytics