线程Word格式文档下载.docx
《线程Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《线程Word格式文档下载.docx(15页珍藏版)》请在冰豆网上搜索。
甚至最简单的Applet也是由多个线程来完成的。
在Java中,任何一个Applet的paint()和update()方法都是由AWT(AbstractWindowToolkit)绘图与事件处理线程调用的,而Applet主要的里程碑方法——init(),start(),stop()和destory()——是由执行该Applet的应用调用的。
单线程的概念没有什么新的地方,真正有趣的是在一个程序中同时使用多个线程来完成不同的任务。
某些地方用轻量进程(LightweightProcess)来代替线程,线程与真正进程的相似性在于它们都是单一顺序控制流。
然而线程被认为轻量是由于它运行于整个程序的上下文内,能使用整个程序共有的资源和程序环境。
作为单一顺序控制流,在运行的程序内线程必须拥有一些资源作为必要的开销。
例如,必须有执行堆栈和程序计数器。
在线程内执行的代码只在它的上下文中起作用,因此某些地方用"
执行上下文"
来代替"
。
折叠编辑本段分类介绍
线程有两个基本类型:
用户级线程:
管理过程全部由用户程序完成,操作系统内核心只对进程进行管理。
系统级线程(核心级线程):
由操作系统内核进行管理。
操作系统内核给应用程序提供相应的系统调用和应用程序接口API,以使用户程序可以创建、执行、撤消线程。
折叠编辑本段语言介绍
另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。
在单个程序中同时运行多个线程完成不同的工作,称为多线程。
折叠属性
在多线程OS中,通常是在一个进程中包括多个线程,每个线程都是作为利用CPU的基本单位,是花费最小开销的实体。
线程具有以下属性。
1)轻型实体
线程中的实体基本上不拥有系统资源,只是有一点必不可少的、能保证独立运行的资源,比如,在每个线程中都应具有一个用于控制线程运行的线程控制块TCB,用于指示被执行指令序列的程序计数器、保留局部变量、少数状态参数和返回地址等的一组寄存器和堆栈。
2)独立调度和分派的基本单位。
在多线程OS中,线程是能独立运行的基本单位,因而也是独立调度和分派的基本单位。
由于线程很“轻”,故线程的切换非常迅速且开销小。
3)可并发执行。
在一个进程中的多个线程之间,可以并发执行,甚至允许在一个进程中所有线程都能并发执行;
同样,不同进程中的线程也能并发执行。
4)共享进程资源。
在同一进程中的各个线程,都可以共享该进程所拥有的资源,这首先表现在:
所有线程都具有相同的地址空间(进程的地址空间),这意味着,线程可以访问该地址空间的每一个虚地址;
此外,还可以访问进程所拥有的已打开文件、定时器、信号量机构等。
折叠线程与进程
线程和进程的区别在于,子进程和父进程有不同的代码和数据空间,而多个线程则共享数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文。
多线程主要是为了节约CPU时间,发挥利用,根据具体情况而定。
线程的运行中需要使用计算机的内存资源和CPU。
通常在一个进程中可以包含若干个线程,它们可以利用进程所拥有的资源。
在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位。
由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统内多个程序间并发执行的程度,从而显著提高系统资源的利用率和吞吐量。
因而近年来推出的通用操作系统都引入了线程,以便进一步提高系统的并发性,并把它视为现代操作系统的一个重要指标。
线程与进程的区别可以归纳为以下几点:
1)地址空间和其它资源(如打开文件):
进程间相互独立,同一进程的各线程间共享。
某进程内的线程在其它进程不可见。
2)通信:
进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。
3)调度和切换:
线程上下文切换比进程上下文切换要快得多。
4)在多线程OS中,进程不是一个可执行的实体。
折叠周期
1.新建2.就绪3.运行4.阻塞5.死亡
折叠线程调度与优先级
有线程进入了就绪状态,需要有线程调度程序来决定何时执行,根据优先级来调度。
折叠线程组
每个线程都是一个线程组的一个成员,线程组把多个线程集成一个对象,通过线程组可以同时对其中的多个线程进行操作。
在生成线程时必须将线程放在指定的线程组,也可以放在缺省的线程组中,缺省的就是生成该线程的线程所在的线程组。
一旦一个线程加入了某个线程组,不能被移出这个组。
折叠守护线程
守护线程是特殊的线程,一般用于在后台为其他线程提供服务.
Java中,isDaemon():
判断一个线程是否为守护线程.
Java中,setDaemon():
设置一个线程为守护线程.
c#守护线程
类1:
守护线程类
/**
* 本线程设置了一个超时时间
* 该线程开始运行后,经过指定超时时间,
* 该线程会抛出一个未检查异常通知调用该线程的程序超时
* 在超时结束前可以调用该类的cancel方法取消计时
* @author solonote
*/
public class TimeoutThread extends Thread{
* 计时器超时时间
private long timeout;
* 计时是否被取消
private boolean isCanceled = false;
* 当计时器超时时抛出的异常
private TimeoutException timeoutException;
* 构造器
* @param timeout 指定超时的时间
public TimeoutThread(long timeout,TimeoutException timeoutErr) {
super();
this.timeout = timeout;
this.timeoutException = timeoutErr;
//设置本线程为守护线程
this.setDaemon(true);
}
* 取消计时
public synchronized void cancel()
{
isCanceled = true;
* 启动超时计时器
public void run()
try {
Thread.sleep(timeout);
if(!
isCanceled)
throw timeoutException;
} catch (InterruptedException e) {
e.printStackTrace();
折叠好处
引入线程的好处:
1创建一个新线程花费的时间少。
2两个线程(在同一进程中的)的切换时间少。
3由于同一个进程内的线程共享内存和文件,所以线程之间互相通信不必调用内核。
4线程能独立执行,能充分利用和发挥处理机与外围设备并行工作的能力。
折叠编辑本段相关信息
折叠Java线程同步的方法
线程的同步是Java多线程编程的难点,往往开发者搞不清楚什么是竞争资源、什么时候需要考虑同步,怎么同步等等问题,当然,这些问题没有很明确的答案,但有些原则问题需要考虑,是否有竞争资源被同时改动的问题?
对于同步,在具体的Java代码中需要完成以下两个操作:
把竞争访问的资源标识为private;
同步哪些修改变量的代码,使用synchronized关键字同步方法或代码。
当然这不是唯一控制并发安全的途径。
synchronized关键字使用说明synchronized只能标记非抽象的方法,不能标识成员变量。
为了演示同步方法的使用,构建了一个信用卡账户,仁人教育起初信用额为100w,然后模拟透支、存款等多个操作。
显然银行账户User对象是个竞争资源,而多个并发操作的是账户方法oper(intx),当然应该在此方法上加上同步,并将账户的余额设为私有变量,禁止直接访问。
/***Java线程:
线程的同步
*
*@authorleizhimin2009-11-411:
23:
32
publicclassTest{
publicstaticvoidmain(String[]args){
Useru=newUser("
张三"
100);
MyThreadt1=newMyThread("
线程A"
u,20);
MyThreadt2=newMyThread("
线程B"
u,-60);
MyThreadt3=newMyThread("
线程C"
u,-80);
MyThreadt4=newMyThread("
线程D"
u,-30);
MyThreadt5=newMyThread("
线程E"
u,32);
MyThreadt6=newMyThread("
线程F"
u,21);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
classMyThreadextendsThread{
privateUseru;
privateinty=0;
MyThread(Stringname,Useru,inty){
super(name);
this.u=u;
this.y=y;
publicvoidrun(){
u.oper(y);
classUser{
privateStringcode;
privateintcash;
User(Stringcode,intcash){
this.code=code;
this.cash=cash;
publicStringgetCode(){
returncode;
publicvoidsetCode(Stringcode){
*业务方法
*@paramx添加x万元
publicsynchronizedvoidoper(intx){
try{
Thread.sleep(10L);
this.cash+=x;
System.out.println(Thread.currentThread().getName()+"
运行结束,增加“"
+x+"
”,当前用户账户余额为:
"
+cash);
}catch(InterruptedExceptione){
@Override
publicStringtoString(){
return"
User{"
+
code='
+code+'
\'
'
cash="
+cash+
}'
;
}输出结果:
线程A运行结束,增加“20”,当前用户账户余额为:
120
线程F运行结束,增加“21”,当前用户账户余额为:
141
线程E运行结束,增加“32”,当前用户账户余额为:
173
线程C运行结束,增加“-80”,当前用户账户余额为:
93
线程B运行结束,增加“-60”,当前用户账户余额为:
33
线程D运行结束,增加“-30”,当前用户账户余额为:
3
Processfinishedwithexitcode0反面教材,不同步的情况,也就是去掉oper(intx)方法的synchronized修饰符,然后运行程序,结果如下:
61
63
Processfinishedwithexitcode0很显然,上面的结果是错误的,导致错误的原因是多个线程并发访问了竞争资源u,并对u的属性做了改动。
可见同步的重要性。
注意:
通过前文可知,线程退出同步方法时将释放掉方法所属对象的锁,但还应该注意的是,同步方法中还可以使用特定的方法对线程进行调度。
这些方法来自于java.lang.Object类。
voidnotify()
唤醒在此对象监视器上等待的单个线程。
voidnotifyAll()
唤醒在此对象监视器上等待的所有线程。
voidwait()
导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法。
voidwait(longtimeout)
导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法,或者超过指定的时间量。
voidwait(longtimeout,intnanos)
导致当前的线程等待,直到其他线程调用此对象的notify()方法或notifyAll()方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量
折叠工作原理
线程是进程中的实体,一个进程可以拥有多个线程,一个线程必须有一个父进程。
线程不拥有系统资源,只有运行必须的一些数据结构;
它与父进程的其它线程共享该进程所拥有的全部资源。
线程可以创建和撤消线程,从而实现程序的并发执行。
一般,线程具有就绪、阻塞和运行三种基本状态。
在多中央处理器的系统里,不同线程可以同时在不同的中央处理器上运行,甚至当它们属于同一个进程时也是如此。
大多数支持多处理器的操作系统都提供编程接口来让进程可以控制自己的线程与各处理器之间的关联度(affinity)。
有时候,线程也称作轻量级进程。
就象进程一样,线程在程序中是独立的、并发的执行路径,每个线程有它自己的堆栈、自己的程序计数器和自己的局部变量。
但是,与分隔的进程相比,进程中的线程之间的隔离程度要小。
它们共享内存、文件句柄和其它每个进程应有的状态。
进程可以支持多个线程,它们看似同时执行,但互相之间并不同步。
一个进程中的多个线程共享相同的内存地址空间,这就意味着它们可以访问相同的变量和对象,而且它们从同一堆中分配对象。
尽管这让线程之间共享信息变得更容易,但您必须小心,确保它们不会妨碍同一进程里的其它线程。
Java线程工具和API看似简单。
但是,编写有效使用线程的复杂程序并不十分容易。
因为有多个线程共存在相同的内存空间中并共享相同的变量,所以您必须小心,确保您的线程不会互相干扰。
折叠线程属性
为了正确有效地使用线程,必须理解线程的各个方面并了解Java实时系统。
必须知道如何提供线程体、线程的生命周期、实时系统如何调度线程、线程组、什么是幽灵线程(DemonThread)。
折叠
(1)线程体
所有的操作都发生在线程体中,在Java中线程体是从Thread类继承的run()方法,或实现Runnable接口的类中的run()方法。
当线程产生并初始化后,实时系统调用它的run()方法。
run()方法内的代码实现所产生线程的行为,它是线程的主要部分。
折叠
(2)线程状态
附图表示了线程在它的生命周期内的任何时刻所能处的状态以及引起状态改变的方法。
这图并不是完整的有限状态图,但基本概括了线程中比较感兴趣和普遍的方面。
以下讨论有关线程生命周期以此为据。
●新线程态(NewThread)
产生一个Thread对象就生成一个新线程。
当线程处于"
新线程"
状态时,仅仅是一个空线程对象,它还没有分配到系统资源。
因此只能启动或终止它。
任何其他操作都会引发异常。
●可运行态(Runnable)
start()方法产生运行线程所必须的资源,调度线程执行,并且调用线程的run()方法。
在这时线程处于可运行态。
该状态不称为运行态是因为这时的线程并不总是一直占用处理机。
特别是对于只有一个处理机的PC而言,任何时刻只能有一个处于可运行态的线程占用处理机。
Java通过调度来实现多线程对处理机的共享。
●非运行态(NotRunnable)
当以下事件发生时,线程进入非运行态。
①suspend()方法被调用;
②sleep()方法被调用;
③线程使用wait()来等待条件变量;
④线程处于I/O等待。
●死亡态(Dead)
当run()方法返回,或别的线程调用stop()方法,线程进入死亡态。
通常Applet使用它的stop()方法来终止它产生的所有线程。
折叠(3)线程优先级
虽然我们说线程是并发运行的。
然而事实常常并非如此。
正如前面谈到的,当系统中只有一个CPU时,以某种顺序在单CPU情况下执行多线程被称为调度(scheduling)。
Java采用的是一种简单、固定的调度法,即固定优先级调度。
这种算法是根据处于可运行态线程的相对优先级来实行调度。
当线程产生时,它继承原线程的优先级。
在需要时可对优先级进行修改。
在任何时刻,如果有多条线程等待运行,系统选择优先级最高的可运行线程运行。
只有当它停止、自动放弃、或由于某种原因成为非运行态低优先级的线程才能运行。
如果两个线程具有相同的优先级,它们将被交替地运行。
Java实时系统的线程调度算法还是强制性的,在任何时刻,如果一个比其他线程优先级都高的线程的状态变为可运行态,实时系统将选择该线程来运行。
折叠(4)幽灵线程
任何一个Java线程都能成为幽灵线程。
它是作为运行于同一个进程内的对象和线程的服务提供者。
例如,HotJava浏览器有一个称为"
后台图片阅读器"
的幽灵线程,它为需要图片的对象和线程从文件系统或网络读入图片。
幽灵线程是应用中典型的独立线程。
它为同一应用中的其他对象和线程提供服务。
幽灵线程的run()方法一般都是无限循环,等待服务请求。
折叠(5)线程组
每个Java线程都是某个线程组的成员。
线程组提供一种机制,使得多个线程集于一个对象内,能对它们实行整体操作。
譬如,你能用一个方法调用来启动或挂起组内的所有线程。
Java线程组由ThreadGroup类实现。
当线程产生时,可以指定线程组或由实时系统将其放入某个缺省的线程组内。
线程只能属于一个线程组,并且当线程产生后不能改变它所属的线程组。
折叠1.SUNSolaris2.3
Solaris支持内核线程、轻权进程和用户线程。
一个进程可有大量用户线程;
大量用户线程复用少量的轻权进程,轻权进程与内核线程一一对应。
用户级线程在调用核心服务时(如文件读写),需要“捆绑(bound)”在一个LWP上。
永久捆绑(一个LWP固定被一个用户级线程占用,该LWP移到LWP池之外)和临时捆绑(从LWP池中临时分配一个未被占用的LWP)。
在调用系统服务时,如果所有LWP已被其他用户级线程所占用(捆绑),则该线程阻塞直到有可用的LWP。
如果LWP执行系统线程时阻塞(如read()调用),则当前捆绑在LWP上的用户级线程也阻塞。
图3用户线程、轻权进程和核心线程的关系
¨
有关的C库函数
/*创建用户级线程*/
intthr_create(void*stack_base,size_tstack_size,
void*(*start_routine)(void*),void*arg,longflags,
thread_t*new_thread_id);
其中flags包括:
THR_BOUND(永久捆绑),THR_NEW_LWP(创建新LWP放入LWP池),若两者同时指定则创建两个新LWP,一个永久捆绑而另一个放入LWP池。
&
sup2;
有关的系统调用
/*在当前进程中创建LWP*/
int_lwp_create(ucontext_t*contextp,unsignedlongflags,
lwpid_t*new_lwp_id);
/*构造LWP上下文*/
void_lwp_makecontext(ucontext_t*ucp,
void(*start_routine)(void*),void*arg,
void*private,caddr_tstack_base,size_tstack_size);
/*注意:
没有进行“捆绑”操作的系统调用*/
折叠2.WindowsNT
NT线程的上下文包括:
寄存器、核心栈、线程环境块和用户栈。
NT线程状态
(1)就绪状态:
进程已获得除处理机外的所需资源,等待执行。
(2)备用状态:
特定处理器的执行对象,系统中每个处理器上只能有一个处于备用状态的线程。
(3)运行状态:
完成描述表切换,线程进入运行状态,直到内核抢先、时间片用完、线程终止或进行等待状态。
(4)等待状态:
线程等待对象句柄,以同步它的执