随便翻译了一页sun认证指南,有人支持我就接着弄,没人看就算了 :P(0分)

你真是个大好人!!!!,
谢谢!!!
 
硬盘挂了……
555~~~~~~
ibm我算记住了!!
 
加油,做完給我一份.
 
支持esimon,是个好同志
 
坚持住!
再次感谢!
 
这两天我忙着恢复数据和休硬盘,一直没时间翻译
呵呵
先跟大家告个假
明后天重新开始把
 
支持支持
再接再厉,一定要坚持啊!
 
活活
前一阵子在忙一个项目,一直没有时间继续翻译
今天再贴一贴
 
第9章 线程(不完全版)
线程
主要内容:
1. 创建,运行和启动一个新线程
2. 线程状态的转化
3. 使线程休眠
在这一部分,我们将要学习有关线程以及如何在程序中使用线程创建复杂行为的知识。一个线程是程序中一个单独的连续控制流。一个线程可以被想象为能够处理一连串指令的软件引擎。在早期的语言中,例如Basic,仅有一个那样的引擎。然而,在现代语言中,可以有很多的线程;他们同时运行,但是相互独立。
各种现代语言使用不同的方法来实现多线程,但是通常都要受到底层操作系统的限制。Java从刚开始设计就考虑到了这个问题,并且,它提供了可以跨平台使用的所有可以简化线程创建的工具。
创建复杂的应用程序时,能够良好掌握线程的使用时必须的,但是学习其中的一些概念是非常困难的。如果这个部分在学习中不是最难的,那么也是相当困难的。有一些主题是很容易掌握的,比如休眠一个线程。其它部分则可能要求在深入学习那些主题欠要通读材料3或4次,比如对象锁和使用其它对象的同步线程。为了通过认证考试,你必须掌握如何运行线程和如何让线程之间有效合作的知识。
创建、运行和启动一个新的线程
设想一个功能丰富的股票代理软件。其中一项功能可能是“下载最新的股票价格”,另外可能还有“检查价格预报”,还有第三个,也是最耗时间的“分析X公司的历史数据”。
在一个单线程环境中,这些操作一个接着一个的执行。只有前面的操作执行完成,下面的操作才能开始。假如一次历史数据分析需要半个小时,并且后来用户选择执行下载和检查操作,那么购买或者出售股票的通知恐怕就会来得太晚了。
这就是从多线程技术极大获益的那类程序。理想情况下,下载操作应该在后台进行(在另外一个线程中)。这将允许其他的内部过程与其同时工作,比如一个需要即刻传送的通知消息。在这个时候,用户可以与程序的其它部分进行交互。另外的一个改进就是,历史数据分析在当前的另一个线程中工作,用户可以在等待运算结果的时候,使用程序的其他功能。
现在,我们该如何使用Java创建这类多线程的功能呢?编写一个多线程程序的第一步是确定被本线程执行的指令集。在Java语言中,你把这些指令写到一个public void run()方法中;这个方法在线程启动的时候被执行。创建线程有两种方法:继承Thread类和实现Runnable接口。
使用继承Thread类的方法创建线程
继承thread类是创建线程的最简单的方法。通常情况下,你希望在一个独立线程中执行的操作是与对象紧密联系在一起的,这样做的主要原因是为了让相同的操作只运行一次。你可以通过定义一个继承自Thread类的新的类来很容易地做到这一点。
定义
Thread类中有一个公有的run()方法。在继承了Thread类后,你可以重载run()方法来实现你需要的功能:

Public class MyThread extends Thread {
Public void run(){
//指令
}
}

主意,run()的标记式并不抛出任何已检查异常。这就意味着你的run()方法同样不能抛出任何异常。如果出现任何未被捕捉的已检查异常,编译器就会报错。

运行
只要你创建了一个累,那么就可以通过调用那个没有参数的构造函数来获得一个该类的一个实例(对象):

MyThread testThread = new MyThread();
当然,你可以使用你所定义的任何一个构造函数。就像其他别的类一样,超类的默认构造函数(Thread()构造函数)会被自动调用。
使用实现Runnable接口的方法创建线程
实现Runnable接口的类可以继承自任何类,这样做的主要目的可能与任何线程操作无关。另外,这个类的实例在它的整个生命周期中能够成为一个或多个线程的目标。这样做要比继承Thread类灵活的多,但是需要多做一步的工作。
定义
Runnable接口只声明了一个方法:
Public void run();

你可以编写一个实现了这个方法的类,就如同下面的这个例子一样:
public class MyRunnable implements Runnable {
public void run(){
//代码
}
}
这个run()方法与Thread类的run()方法是类似的,所以他不会抛出任何已检查的异常。
运行
一旦你编写了一个类,你就需要调用你定义的或者默认的构造函数来创建它的实例:

MyRunnable firstRunnable = new MyRunnable();
这个实例就是线程的目标。然后,你就可以把这个目标作为参数来创建一个Thread类的对象:
Thread testThread = new Thread(firstRunnable);
启动一个线程的实例
不管你是从Thread类的子类创建的还是从Runnable目标创建的,现在这个线程的实例与其他的对象没有任何的不同。他有你能够访问的变量和能够调用的方法,但是他自己现在什么也干不了。他已经为运行做好了准备,但是他并没有开始运行,除非你让他开始运行,否则它不会自己启动的。你需要做的是,调用这个线程实例的start()方法:

testThread.start();
这将会启动一个新的你的指令的执行流并且立即返回。从一刻开始,你在run()方法里面指定的指令将会与start()方法后的任何内容并行运行。
在使用runnable目标的情况下,它的run()方法没有被直接调用的,但是它被线程实例的默认run方法所调用。所以效果是一样的;现在有一个单独的线程正在执行你在run()方法里指定的指令。
在一个线程里面,你只能调用start()方法一次。如果你尝试运行一个已经启动的线程,你会得到一个IllegalThradStateException的异常。这是一个非检查的异常,所以你不用操心去捕捉它。
线程状态的转换
线程在运行状态的情况是我们最感兴趣的。他们与其他的线程并发执行他们的run()方法,他们合作,共享资源,为了完成各自的任务,他们甚至相互竞争。
因为在单CPU的计算机中一个时刻只能有一条指令执行,所以线程需要轮流执行。通常线程之间的切换非常迅速,给用户的感觉就是并行的(我们稍候会讨论这个问题)。就现在来说,请记住一个线程在一次运行时并不一定会执行全部指令;它可能会随时被切换并等待下一次执行。如果系统有多个CPU,那么线程就可以真正的并发执行了。
就算一个线程启动了,也不保证它能一直运行下去。Java虚拟机(JVM)会自动切换一个新的线程,分配CPU时间让它运行一会。这些状态是用来描述在执行的时候人一时刻一个线程的状态的标准Java术语。一个线程有5种主要的状态:
 New thread 这是线程刚被创建还没有调用start()方法时的状态。调用线程的构造函数,并不能执行线程!只要线程启动了,线程调度程序就可以开始为他分配CPU时间。
 Runnable 这是线程已经可以运行,但是还没有分配到CPU时间时的状态。
 Running 这是线程调度程序给线程分配了CPU时间片后,线程所处的状态。一个正在运行的线程可以随时转换成其他状态,例如:waiting,runnable或者dead。
 Waiting/blocking 一个线程处于waiting状态,字面上的解释就是等待一些条件被满足。一旦条件被满足,他就会从waiting状态转换成为runnable状态,参见图表1。线程转入waiting状态,是因为调用了sleep()或者wait()方法。(我们稍候讨论这个问题。)Sun把它归诸于Not Runnable状态。
 Dead 当run()方法完成之后,线程会中止执行。这个时候,线程就dead了。一个dead的线程不能够重新启动。

图1 线程状态转换
让我们复习一下一个典型线程的生命周期。当构造函数执行后,线程就运行了。一旦调用了start()方法,那么线程就进入了runnable状态直到线程调度程序为他分配CPU时间片。线程在这个状态下只能转换到一种状态,也就是running状态(图一)。当处于running状态时,run()方法的部分或者全部将会被执行。如果调度程序把时间片分配给了另外的线程,当前线程将会再次进入runnable状态。
如果调用了sleep()方法,线程将会进入waiting状态。只要经过了特定的时间,线程会重新进入runnable状态并最终进入running状态。当run()方法中的代码运行完毕,线程就转入dead状态。没有任何方法可以让线程离开dead状态,这点和人类是一样的。
注意waiting和blocking状态取决于在线程控制之外的事件。如果这个事件从没有发生,线程有可能永久性的卡住。这种情况被称作deadlock,我们将会在后面进行讨论。
休眠线程
有时候我们需要推迟一个线程的执行一小会儿。我们会在这里讨论这样做的理由和如何做到。
假定一个正在循环之行的虚拟线程,它正在下在最新的股票价格并且进行分析。一个一个的下载价格可能是在浪费时间,因为他们大部分也许很相似,甚至,这根本就是一种浪费,因为它占用了太多的带宽。
解决这个问题的最简单的方法是每次下载间隔5分钟。你在Java中可以使用线程的sleep()方法做到这一点。
这是一个是当前线程休眠指定毫秒时间的静态方法,如下:
Thread.sleep(5*60*1000);
Sleep()方法接受long型的参数,这个参数是用来制定休眠时间的毫秒数。前面的例子是使当前线程在其他线程保持运行的时候休眠5分钟。Sleep()方法还会抛出类型为InterruptedException的例外,这个例外是必须被处理的。
当一个线程正在休眠,另外的线程可能使用线程实例方法interrupt()去中断它:
sleepingThread.interrupt();
如果一个线程已经被中断了,一个内部的标志(在被中断的实例中)会被置位,并且这个休眠的线程将会提前唤醒。这时Sleep()方法会立即抛出一个InterruptedException。只要这个标志被置位了,那么调用sleep()方法不会让线程进入休眠,而是会抛出一个例外。
正是因为这个例外,所以sleep()调用通常都是放置在try-catch块中,如下:
try{
Thread.sleep(sleepingTime);
}
catch(InterruptedException e){
//处理
}
InterruptedException是一个已检查的例外,所以如果你没有捕捉它或者指定当前线程抛出它,编译器将会报错。
你应该了解线程将要运行的内容并且能够预知该线程是否会被中断。如果你能肯定没有其他线程会中断本线程,或者你并不关心如何退出,那么通常你不需要在catch块中写任何代码。在本例中,这是一个退出循环操作的好机会。这个线程的run()方法应该像是下面这样:

public void run(){
while(true){
//下载股票价格
//分析并且报告
try{
Thread.sleep(5*60*1000);
}catch(InterruptedException e){
bread;
}
}
}
在这个例子里面,线程会下载股票价格,分析并进行报告,然后休眠5分钟。在休眠过后(如果没有中断)它将会再次开始循环。
在sleeping状态时,线程并没有获得CPU时间片。只有休眠期过后或者线程被中断,它才有重新运行的权利。注意,Java里面的实例是没有sleep()方法的,所以直接使其他线程休眠是不可能的。
在任意时刻,一个线程可以通过使用下面的静态方法来检查自己的中断状态:
Thread.interrupted();//返回布尔值
这个方法也会自动清空中断标志,所以如果同时调用interrupted()方法2次,第二个一定返回false。
任何线程都可以动过使用下面这个实例方法来查询其他线程的终端状态:
otherThread.isInterrupted();//返回布尔值
这个方法,与interrupted()相反,不会对中断标志产生任何影响。改变一个线程的中断状态只有一个方法,那就是在目标线程上调用interrupt()方法。
 
事情还是比较多
感觉翻译得不太好
如果有不通顺或者不太明白的地方,请随便说
 
对于这种无私奉献的雷锋精神要大力宣扬!
 
唉~~~
不做翻译还真不知道自己中文烂阿
早知道高中好好学语文了
 
大力支持!
不过,我觉得还是召集一批懂的人,
给你审稿,一边大家审稿讨论,一边你翻译,这样会准确些,更具有价值,
不要意思,我只是想保证翻译的质量,以免作无用之工,或者误人子弟!
无恶意!
 
我想找批人共同翻译<Delphi精要>,谁有这个兴趣?
 
强烈支持,希望这样的帖子越来越多
 
举双手,双脚支持!
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
902
DelphiTeacher的专栏
D
D
回复
0
查看
1K
DelphiTeacher的专栏
D
D
回复
0
查看
2K
DelphiTeacher的专栏
D
顶部