1.什么是线程
![](/icons/39965yi.gif)
般来说,我们把正在计算机中执行
![](/icons/39965de.gif)
![](/icons/39965chengxu.gif)
叫做"进程"(Process) ,而不将其称为
![](/icons/39965chengxu.gif)
(Program)
![](/icons/39965dou2.gif)
所谓"线程"(Thread),是"进程"中某个单
![](/icons/39965yi.gif)
顺序
![](/icons/39965de.gif)
控制流
![](/icons/39965dou2.gif)
新兴
![](/icons/39965de.gif)
操作系统,如Mac,Windows NT,Windows 95等,大多采用多线程
![](/icons/39965de.gif)
概念,把线程视为基本执行单位
![](/icons/39965dou2.gif)
线程也是Java中
![](/icons/39965de.gif)
相当重要
![](/icons/39965de.gif)
组成部分的
![](/icons/39965yi.gif)
甚至最简单
![](/icons/39965de.gif)
Applet也是由多个线程来完成
![](/icons/39965de.gif)
![](/icons/39965dou2.gif)
在Java中,任何
![](/icons/39965yi.gif)
个Applet
![](/icons/39965de.gif)
pa
![](/icons/39965int.gif)
![](/icons/39965kh.gif)
和update
![](/icons/39965kh.gif)
思路方法都是由AWT(Abstract Window Toolkit)绘图和事件处理线程
![](/icons/39965diaoyong.gif)
![](/icons/39965de.gif)
,而Applet 主要
![](/icons/39965de.gif)
里程碑思路方法——init
![](/icons/39965kh.gif)
,start
![](/icons/39965kh.gif)
,stop
![](/icons/39965kh.gif)
和destory
![](/icons/39965kh.gif)
——是由执行该Applet
![](/icons/39965de.gif)
应用
![](/icons/39965diaoyong.gif)
![](/icons/39965de.gif)
单线程
![](/icons/39965de.gif)
概念没有什么新
![](/icons/39965de.gif)
地方,真正有趣
![](/icons/39965de.gif)
是在
![](/icons/39965yi.gif)
个
![](/icons/39965chengxu.gif)
中同时使用多个线程来完成区别
![](/icons/39965de.gif)
任务
![](/icons/39965dou2.gif)
某些地方用轻量进程(Lightweig ht Process)来代替线程和真正进程
![](/icons/39965de.gif)
相似性在于它们都是单
![](/icons/39965yi.gif)
顺序控制流
![](/icons/39965dou2.gif)
然而线程被认为轻量是由于它运行于整个
![](/icons/39965chengxu.gif)
![](/icons/39965de.gif)
上下文内,能使用整个
![](/icons/39965chengxu.gif)
共有
![](/icons/39965de.gif)
资源和
![](/icons/39965chengxu.gif)
环境
作为单
![](/icons/39965yi.gif)
顺序控制流,在运行
![](/icons/39965de.gif)
![](/icons/39965chengxu.gif)
内线程必须拥有
![](/icons/39965yi.gif)
些资源作为必要
![](/icons/39965de.gif)
开销
![](/icons/39965dou2.gif)
例如,必须有执行堆栈和
![](/icons/39965chengxu.gif)
计数器
![](/icons/39965dou2.gif)
在线程内执行
![](/icons/39965de.gif)
代码只在它
![](/icons/39965de.gif)
上下文中起作用,因此某些地方用"执行上下文"来代替"线程"
2.线程属性
为了正确有效地使用线程,必须理解线程
![](/icons/39965de.gif)
各个方面并了解Java 实时系统
![](/icons/39965dou2.gif)
必须知道如何提供线程体、线程
![](/icons/39965de.gif)
生命周期、实时系统如 何调度线程、线程组、什么是幽灵线程(Demo nThread)
(1)线程体
所有
![](/icons/39965de.gif)
操作都发生在线程体中,在Java中线程体是从Thread类继承
![](/icons/39965de.gif)
run
![](/icons/39965kh.gif)
思路方法,或实现Runnable接口
![](/icons/39965de.gif)
类中
![](/icons/39965de.gif)
run
![](/icons/39965kh.gif)
思路方法
![](/icons/39965dou2.gif)
当线程产生并
![](/icons/39965chushi.gif)
化后,实时系统
![](/icons/39965diaoyong.gif)
它
![](/icons/39965de.gif)
run
![](/icons/39965kh.gif)
思路方法
![](/icons/39965dou2.gif)
run
![](/icons/39965kh.gif)
思路方法内
![](/icons/39965de.gif)
代码实现所产生线程
![](/icons/39965de.gif)
行为,它是线程
![](/icons/39965de.gif)
主要部分
(2)线程状态
附图表示了线程在它
![](/icons/39965de.gif)
生命周期内
![](/icons/39965de.gif)
任何时刻所能处
![](/icons/39965de.gif)
状态以及引起状态改变
![](/icons/39965de.gif)
思路方法
![](/icons/39965dou2.gif)
这图并不是完整
![](/icons/39965de.gif)
有限状态图,但基本概括了线程中比较感兴趣和普遍
![](/icons/39965de.gif)
方面
![](/icons/39965dou2.gif)
以下讨论有关线程生命周期以此为据
●新线程态(New Thread)
产生
![](/icons/39965yi.gif)
个Thread对象就生成
![](/icons/39965yi.gif)
个新线程
![](/icons/39965dou2.gif)
当线程处于"新线程"状态时,仅仅是
![](/icons/39965yi.gif)
个空线程对象,它还没有分配到系统资源
![](/icons/39965dou2.gif)
因此只能启动或终止它
![](/icons/39965dou2.gif)
任何其他操作都会引发异常
●可运行态(Runnable)
start
![](/icons/39965kh.gif)
思路方法产生运行线程所必须
![](/icons/39965de.gif)
资源,调度线程执行,并且
![](/icons/39965diaoyong.gif)
线程
![](/icons/39965de.gif)
run
![](/icons/39965kh.gif)
思路方法
![](/icons/39965dou2.gif)
在这时线程处于可运行态
![](/icons/39965dou2.gif)
该状态不称为运行态是
![](/icons/39965yinwei.gif)
这时
![](/icons/39965de.gif)
线程并不总是
![](/icons/39965yi.gif)
直占用处理机
![](/icons/39965dou2.gif)
特别是对于只有
![](/icons/39965yi.gif)
个处理机
![](/icons/39965de.gif)
PC而言,任何时刻只能有
![](/icons/39965yi.gif)
个处于可运行态
![](/icons/39965de.gif)
线程占用处理 机
![](/icons/39965dou2.gif)
Java通过调度来实现多线程对处理机
![](/icons/39965de.gif)
共享
●非运行态(Not Runnable)
当以下事件发生时,线程进入非运行态
①suspend
![](/icons/39965kh.gif)
思路方法被
![](/icons/39965diaoyong.gif)
;
②sleep
![](/icons/39965kh.gif)
思路方法被
![](/icons/39965diaoyong.gif)
;
③线程使用wait
![](/icons/39965kh.gif)
来等待条件变量;
④线程处于I/O等待
●死亡态(Dead)
当run
![](/icons/39965kh.gif)
思路方法返回,或别
![](/icons/39965de.gif)
线程
![](/icons/39965diaoyong.gif)
stop
![](/icons/39965kh.gif)
思路方法,线程进入死亡态
![](/icons/39965dou2.gif)
通常Applet使用它
![](/icons/39965de.gif)
stop
![](/icons/39965kh.gif)
思路方法来终止它产生
![](/icons/39965de.gif)
所有线程
(3)线程优先级
虽然我们说线程是并发运行
![](/icons/39965de.gif)
![](/icons/39965dou2.gif)
然而事实常常并非如此
![](/icons/39965dou2.gif)
正如前面谈到
![](/icons/39965de.gif)
,当系统中只有
![](/icons/39965yi.gif)
个CPU时,以某种顺序在单CPU情况下执行多线程被称为调度(scheduling)
![](/icons/39965dou2.gif)
Java采用
![](/icons/39965de.gif)
是
![](/icons/39965yi.gif)
种简单、固定
![](/icons/39965de.gif)
调度法,即固定优先级调度
![](/icons/39965dou2.gif)
这种算法是根据处于可运行态线程
![](/icons/39965de.gif)
相对优先级来实行调度
![](/icons/39965dou2.gif)
当线程产生时,它继承原线程
![](/icons/39965de.gif)
优先级
![](/icons/39965dou2.gif)
在需要时可对优先级进行修改
![](/icons/39965dou2.gif)
在任何时刻,如果有多条线程等待运行,系统选择优先级最高
![](/icons/39965de.gif)
可运行线程运行
![](/icons/39965dou2.gif)
只有当它停止、自动放弃、或由于某种原因成为非运行态低优先级
![](/icons/39965de.gif)
线程才能运行
![](/icons/39965dou2.gif)
如果两个线程具有相同
![](/icons/39965de.gif)
优先级,它们将被交替地运行
Java实时系统
![](/icons/39965de.gif)
线程调度算法还是强制性
![](/icons/39965de.gif)
,在任何时刻,如果
![](/icons/39965yi.gif)
个比其他线程优先级都高
![](/icons/39965de.gif)
线程
![](/icons/39965de.gif)
状态变为可运行态,实时系统将选择该线程来运行
(4)幽灵线程
任何
![](/icons/39965yi.gif)
个Java线程都能成为幽灵线程
![](/icons/39965dou2.gif)
它是作为运行于同
![](/icons/39965yi.gif)
个进程内
![](/icons/39965de.gif)
对象和线程
![](/icons/39965de.gif)
服务提供者
![](/icons/39965dou2.gif)
例如,HotJava浏览器有
![](/icons/39965yi.gif)
个称为" 后台图片阅读器"
![](/icons/39965de.gif)
幽灵线程,它为需要图片
![](/icons/39965de.gif)
对象和线程从文件系统或网络读入图片
幽灵线程是应用中典型
![](/icons/39965de.gif)
独立线程
![](/icons/39965dou2.gif)
它为同
![](/icons/39965yi.gif)
应用中
![](/icons/39965de.gif)
其他对象和线程提供服务
![](/icons/39965dou2.gif)
幽灵线程
![](/icons/39965de.gif)
run
![](/icons/39965kh.gif)
思路方法
![](/icons/39965yi.gif)
般都是无限循环,等待服务请求
(5)线程组
每个Java线程都是某个线程组
![](/icons/39965de.gif)
成员
![](/icons/39965dou2.gif)
线程组提供
![](/icons/39965yi.gif)
种机制,使得多个线程集于
![](/icons/39965yi.gif)
个对象内,能对它们实行整体操作
![](/icons/39965dou2.gif)
譬如,你能用
![](/icons/39965yi.gif)
个思路方法
![](/icons/39965diaoyong.gif)
来启动或挂起组内
![](/icons/39965de.gif)
所有线程
![](/icons/39965dou2.gif)
Java线程组由ThreadGroup类实现
当线程产生时,可以指定线程组或由实时系统将其放入某个缺省
![](/icons/39965de.gif)
线程组内
![](/icons/39965dou2.gif)
线程只能属于
![](/icons/39965yi.gif)
个线程组,并且当线程产生后不能改变它所属
![](/icons/39965de.gif)
线程组
3.多线程
对于多线程
![](/icons/39965de.gif)
好处这就不多说了
![](/icons/39965dou2.gif)
但是,它同样也带来了某些新
![](/icons/39965de.gif)
麻烦
![](/icons/39965dou2.gif)
只要在设计
![](/icons/39965chengxu.gif)
时特别小心留意,克服这些麻烦并不算太困难
(1)同步线程
许多线程在执行中必须考虑和其他线程的间共享数据或协调执行状态
![](/icons/39965dou2.gif)
这就需要同步机制
![](/icons/39965dou2.gif)
在Java中每个对象都有
![](/icons/39965yi.gif)
把锁和的对应
![](/icons/39965dou2.gif)
但Java不提供单独
![](/icons/39965de.gif)
lock和unlock操作
![](/icons/39965dou2.gif)
它由高层
![](/icons/39965de.gif)
结构隐式实现, 来保证操作
![](/icons/39965de.gif)
对应
![](/icons/39965dou2.gif)
(然而,我们注意到Java虚拟机提供单独
![](/icons/39965de.gif)
monito renter和monitorexit指令来实现lock和unlock操作
![](/icons/39965dou2.gif)
)
synchronized语句计算
![](/icons/39965yi.gif)
个对象引用,试图对该对象完成锁操作, 并且在完成锁操作前停止处理
![](/icons/39965dou2.gif)
当锁操作完成synchronized语句体得到执行
![](/icons/39965dou2.gif)
当语句体执行完毕(无论正常或异常),解锁操作自动完成
![](/icons/39965dou2.gif)
作为面向对象
![](/icons/39965de.gif)
语言,synchronized经常和思路方法连用
![](/icons/39965dou2.gif)
![](/icons/39965yi.gif)
种比较好
![](/icons/39965de.gif)
办法是,如果某个变量由
![](/icons/39965yi.gif)
个线程赋值并由别
![](/icons/39965de.gif)
线程引用或赋值,那么所有对该变量
![](/icons/39965de.gif)
访问都必须在某个synchromized语句或synchronized思路方法内
现在假设
![](/icons/39965yi.gif)
种情况:线程1和线程2都要访问某个数据区,并且要求线程1
![](/icons/39965de.gif)
访问先于线程2, 则这时仅用synchronized是不能解决问题
![](/icons/39965de.gif)
![](/icons/39965dou2.gif)
这在Unix或WindowsNT中可用Simaphore来实现
![](/icons/39965dou2.gif)
而Java并不提供
![](/icons/39965dou2.gif)
在Java中提供
![](/icons/39965de.gif)
是wait
![](/icons/39965kh.gif)
和not
![](/icons/39965if.gif)
y
![](/icons/39965kh.gif)
机制
![](/icons/39965dou2.gif)
使用如下:
synchronized method - 1(...) {
call by thread 1.
//access data area;
available = true;
not
![](/icons/39965if.gif)
y
}
synchronized method - 2(...) { //call by thread 2.
while (!available) {
try {
wait
![](/icons/39965kh.gif)
; //wait for not
![](/icons/39965if.gif)
y
![](/icons/39965kh.gif)
.
} catch (Interrupted Exception e) {
}
}
//access data area
}
其中available是类成员变量,置初值为false
如果在method-2中检查available为假,则
![](/icons/39965diaoyong.gif)
wait
![](/icons/39965kh.gif)
![](/icons/39965dou2.gif)
wait
![](/icons/39965kh.gif)
![](/icons/39965de.gif)
作用是使线程2进入非运行态,并且解锁
![](/icons/39965dou2.gif)
在这种情况下,method-1可以被线程1
![](/icons/39965diaoyong.gif)
![](/icons/39965dou2.gif)
当执行not
![](/icons/39965if.gif)
y
![](/icons/39965kh.gif)
后
![](/icons/39965dou2.gif)
线程2由非运行态转变为可运行态
![](/icons/39965dou2.gif)
当method-1
![](/icons/39965diaoyong.gif)
返回后
![](/icons/39965dou2.gif)
线程2
可重新对该对象加锁,加锁成功后执行wait
![](/icons/39965kh.gif)
返回后
![](/icons/39965de.gif)
指令
![](/icons/39965dou2.gif)
这种机制也能适用于其他更复杂
![](/icons/39965de.gif)
情况
(2)死锁
如果
![](/icons/39965chengxu.gif)
中有几个竞争资源
![](/icons/39965de.gif)
并发线程,那么保证均衡是很重要
![](/icons/39965de.gif)
![](/icons/39965dou2.gif)
系统均衡是指每个线程在执行过程中都能充分访问有限
![](/icons/39965de.gif)
资源
![](/icons/39965dou2.gif)
系统中没有饿死和死锁
![](/icons/39965de.gif)
线程
![](/icons/39965dou2.gif)
Java并不提供对死锁
![](/icons/39965de.gif)
检测机制
![](/icons/39965dou2.gif)
对大多数
![](/icons/39965de.gif)
Java
![](/icons/39965chengxu.gif)
员来说防止死锁是
![](/icons/39965yi.gif)
种较好
![](/icons/39965de.gif)
选择
![](/icons/39965dou2.gif)
最简单
![](/icons/39965de.gif)
防止死锁
![](/icons/39965de.gif)
思路方法是对竞争
![](/icons/39965de.gif)
资源引入序号,如果
![](/icons/39965yi.gif)
个线程需要几个资源,那么它必须先得到小序号
![](/icons/39965de.gif)
资源,再申请大序号
![](/icons/39965de.gif)
资源
4.小结
线程是Java中
![](/icons/39965de.gif)
重要内容,多线程是Java
![](/icons/39965de.gif)
![](/icons/39965yi.gif)
个特点
![](/icons/39965dou2.gif)
虽然Java
![](/icons/39965de.gif)
同步互斥不如某些系统那么丰富,但适当地使用它们也能收到满意
![](/icons/39965de.gif)
效果
run思路方法返回后线程进入死亡态
死亡态(Dead)
当run
![](/icons/39965kh.gif)
思路方法返回,或别
![](/icons/39965de.gif)
线程
![](/icons/39965diaoyong.gif)
stop
![](/icons/39965kh.gif)
思路方法,线程进入死亡态
![](/icons/39965dou2.gif)
通常Applet使用它
![](/icons/39965de.gif)
stop
![](/icons/39965kh.gif)
思路方法来终止它产生
![](/icons/39965de.gif)
所有线程