java第十一章课后习题答案

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

11.1、
线程的概念:Thread 每个正在系统上运行的程序都是一个进程。

每个进程包含一到多个线程。

进程也可能是整个程序或者是部分程序的动态执行。

线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行。

也可以把它理解为代码运行的上下文。

所以线程基本上是轻量级的进程,它负责在单个程序里执行多任务。

通常由操作系统负责多个线程的调度和执行。

多线程的概念:多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。

线程是在同一时间需要完成多项任务的时候实现的。

多线程的优点:使用线程可以把占据长时间的程序中的任务放到后台去处理用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度·11.2、
答:一个线程从创建到不再有用称为线程的生命周期。

线程的生命周期可以分为4个状态:
①创建(new)状态;
②可运行(runnable)状态;
⑧不可运行(not runnable)状态;
④消亡(dead)状态。

创建状态是指创建一个线程所对应的对象的过程。

Java系统中,这些对象都是从java. lang包内一个称为Thread的类用关键字new创建的。

刚创建的线程不能执行,必须向系统进行注册、分配必要的资源后才能进入可运行状态,这个步骤是由start操作完成的。

而处于可运行状态的线程也未必一定处于运行中,它有可能由于外部的I/O请求而处于不可运行状态。

进入消亡状态后,此线程就不再存在了。

答:一个线程创建之后,总是处于其生命周期的4个状态之一中。

线程的状态表明此线程当前正在进行的活动,而线程的状态是可以通过程序来进行控制的,就是说,可以对线程进行操作来改变状态。

这些操作包括启动(start)、终止(stop)、睡眠(sleep)、挂起(suspend)、恢复(resume)、等待(wait)和通知(notify)。

每一个操作都对应了一个方法,这些方法是由软件包ng提供的。

①创建(new)状态
如果创建了一个线程而没有启动它,那么,此线程就处于创建状态。

比如,下述语句执行以后,使系统有了一个处于创建状态的线程myThread:
Thread myThread= new MyThreadClass();
其中,MyThreadClass()是Thread的子类,而Thread是由Java系统的ng软件包提供的。

处于创建状态的线程还没有获得应有的资源,所以,这是一个空的线程。

线程只有通过启动后,系统才会为它分配资源。

对处于创建状态的线程可以进行两种操作:一是启动 (start)操作,使其进入可运行状态,二是终止(stop)操作,使其进入消亡状态。

如果进入到消亡状态,那么,此后这个线程就不能进入其他状态,也就是说,
它不再存在了。

start方法是对应启动操作的方法,其具体功能是为线程分配必要的系统资源;将线程设置为可运行状态,从而可以使系统调度这个线程。

②可运行(runnable)状态
如果对一个处于创建状态的线程进行启动操作,则此线程便进入可运行状态。

仍以前面创建的myThread线程为例,用下列语句:myThread.start(); 则线程myThread进入可运行状态。

上述语句实质上是调用了线程体即run()方法。

注意, run()方法包含在myThread线程中,也就是先由ng包的Thread类将run()方法传递给子类MyThreadClass(),再通过创建线程由于类MyThreadClass()传递给线程 myThread。

线程处于可运行状态只说明它具备了运行条件,但可运行状态并不一定是运行状态。

因为在单处理器系统中运行多线程程序,实际上在一个时间点只有一个线程在运行,而系统中往往有多个线程同时处于可运行状态。

系统通过快速切换和调度使所有可运行线程共享处理器,造成宏观上的多线程并发运行。

可见,一个线程是否处于运行状态,除了必须处于可运行状态外,还取决于系统的调度。

在可运行状态可以进行多种操作,最通常的是从run()方法正常退出而使线程结束,进入消亡状态。

此外,还可以有如下操作:挂起操作,通过调用suspend方法来实现;
睡眠操作,通过调用sleep方法来实现;
等待操作,通过调用wait方法来实现;
退让操作,通过调用yield方法来实现;
终止操作,通过调用stop方法来实现。

前面三种操作都会使一个处于可运行状态的线程进入不可运行状态。

比如,仍以 myThread线程为例,当其处于可运行状态后,再用如下语句:
myThreadsleep(5000);
则调用sleep方法使myThread线程睡眠5秒(5000毫秒)。

这5秒内,此线程不能被系统调度运行,只有过5秒后,myThread线程才会醒来并自动回到可运行状态。

如果一个线程被执行挂起操作而转到不可运行状态,则必须通过调用恢复(resume)操作,才能使这个线程再回到可运行状态。

退让操作是使某个线程把CPU控制权提前转交给同级优先权的其他线程。

对可运行状态的线程也可以通过调用stop方法使其进入消亡状态。

③不可运行(not runnable)状态
不可运行状态都是由可运行状态转变来的。

一个处于可运行状态的线程,如果遇到挂起 (suspend)操作、睡眠(sleep)操作或者等待(wait)操作,就会进入不可运行状态。

另外,如果一个线程是和I/O 操作有关的,那么,在执行I/O指令时,由于外设速度远远低于处理
器速度而使线程受到阻塞,从而进入不可运行状态,只有外设完成输入/输出之后,该线程才会自动回到可运行状态。

线程进入不可运行状态后,还可以再回到可运行状态。

通常有三种途径使其恢复到可运行状态。

一是自动恢复。

通过睡眠(sleep)操作而进入不可运行状态的线程会在过了指定睡眠时间以后自动恢复到可运行状态;由于I/O阻塞而进入不可运行状态的线程在外设完成I/O操作后,自动恢复到可运行状态。

二是用恢复(resume)方法使其恢复。

如果一个线程由于挂起(suspend)操作而从可运行状态进入不可运行状态,那么,必须用恢复(resume)操作使其再恢复到可运行状态。

三是用通知(notify或notiyA11)方法使其恢复。

如果一个处于可运行状态的线程由于等待(wait)操作面转入不可运行状态,那么,必须通过调用notify方法或notifyAll方法才能使其恢复到可运行状态。

采用等待操作往往是由于线程需要等待某个条件变量,当获得此条件变量后,便可由notify或notifyAll方法使线程恢复到可运行状态。

恢复到可运行状态的每一种途径都是有针对性的,不能交叉。

比如,对由于阻塞而进入不可运行状态的线程采用恢复操作将是无效的。

在不可运行状态,也可由终止(stop)操作使其进入消亡状态。

④消亡(dead)状态
一个线程可以由其他任何一个状态通过终止(stop)操作而进入消
亡状态。

线程一旦进入消亡状态,那它就不再存在,所以也不可能再转到其他状态。

通常,在一个应用程序运行时,如果通过其他外部命令终止当前应用程序,那么就会调用stop方法终止线程。

但是,最正常、最常见的途径是由于线程在可运行状态正常完成自身的任务而“寿终正寝”,从而进入消亡状态,这个完成任务的动作是由run方法实现的。

11.3、在Java中创建线程有两种方法:继承Thread类和实现Runnable 接口
11.4、
Thread类中包含了重写run方法。

start()启动线程sleep(毫秒数)启动后停止的毫秒数
Run()方法被称为线程体是因为它是整个线程的核心,线程所要完成的任务代码都定义在run()方法中
11.5、
在选择创建线程的方法时,要考虑两种方法的优劣势,找到更适合你程序的方法。

两种方式的比较
首先分析两种方式的输出结果,同样是创建了两个线程,为什么结果不一样呢?
使用实现Runnable接口方式创建线程可以共享同一个目标对象(TreadDemo1 tt=new TreadDemo1();),实现了多个相同线程处理同一份资源。

然后再看一段来自JDK的解释:
Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。

类必须定义一个称为run 的无参数方法。

设计该接口的目的是为希望在活动时执行代码的对象提供一个公共协议。

例如,Thread 类实现了Runnable。

激活的意思是说某个线程已启动并且尚未停止。

此外,Runnable 为非 Thread 子类的类提供了一种激活方式。

通过实例化某个Thread 实例并将自身作为运行目标,就可以运行实现Runnable 的类而无需创建 Thread 的子类。

大多数情况下,如果只想重写run() 方法,而不重写其他 Thread 方法,那么应使用Runnable 接口。

这很重要,因为除非程序员打算修改或增强类的基本行为,否则不应为该类创建子类。

采用继承Thread类方式:
(1)优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。

(2)缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。

采用实现Runnable接口方式:
(1)优点:线程类只是实现了Runable接口,还可以继承其他的类。

在这种方式下,可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。

(2)缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。

11.6、
Java的线程调度采用如下的优先级策略:(1)优先级高的先执行,优先级低的后执行(2)多线程系统会自动为每个线程分配一个优先级,默认时,继承其父类的优先级(3)任务紧急的线程,其优先级较高(4)同优先级的线程按“先进先出”的原则。

11.7、
(1)sleep()
使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁。

也就是说如果有synchronized同步快,其他线程仍然不能访问共享数据。

注意该方法要捕捉异常。

例如有两个线程同时执行(没有synchronized)一个线程优先级为MAX_PRIORITY,另一个为MIN_PRIORITY,如果没有Sleep()方法,只有高优先级的线程执行完毕后,低优先级的线程才能够执行;但是高优先级的线程sleep(500)后,低优先级就有机会执行了。

总之,sleep()可以使低优先级的线程得到执行的机会,当然也可以让同优先级、高优先级的线程有执行的机会。

(2)yield()
该方法与sleep()类似,只是不能由用户指定暂停多长时间,并且yield()方法只能让同优先级的线程有执行的机会。

11.8、
不加入线程的同步,可能导致冲突异常,不应该访问的,被访问,或者数据被无故修改,不同步会造成数据访问混乱达不到目的效果。

实现同步机制有两个方法:
1。

同步代码块:
synchronized(同一个数据){} 同一个数据:就是N条线程同时访问一个数据。

2。

同步方法:
public synchronized 数据返回类型方法名(){}
就是使用synchronized 来修饰某个方法,则该方法称为同步方法。

对于同步方法而言,无需显示指定同步监视器,同步方法的同步监视器是this 也就是该对象的本身(这里指的对象本身有点含糊,其实就是调用该同步方法的对象)通过使用同步方法,可非常方便的将某类变成线程安全的类,具有如下特征:
1,
所谓死锁: 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将该类的对象可以被多个线程安全的访问。

2,每个线程调用该对象的任意方法之后,都将得到正确的结果。

3,每个线程调用该对象的任意方法之后,该对象状态依然保持合理状态。

11.9、
无法推进下去。

Java中的同步机制可以防止死锁的发生。

避免死锁的有效原则是:
①当线程因为某个条件未满足而受阻,不能让其继续占用资源。

②如果有多个对象需要互斥访问,应确定线程获得锁的顺序,程间同并保证整个程序以相反的顺序释放锁。

然而避免死锁发生的方法是:如果有多个对象要被同步,那就制定一个规则来决定以何种顺序来获得这些死锁,并在整个程序中遵循这个顺序。

11.10
import ng.*;
import java.io.*;
public class ThreadTest{
public static void main(String []args){
Object dummy=new Object();
FirstThread ft=new FirstThread(dummy);
SecondThread st=new SecondThread(dummy);
ft.start();
st.start();
}//end main()
}//end public class ThreadTest
class FirstThread extends Thread {
Object dummy;
public FirstThread(Object s){
dummy=s;
System.out.println("第一个进程被执行了");
}
public void run(){
try{
System.out.println("第一个进程已经开始了");
System.out.println("第一个进程正在等待第二个进程");
synchronized(dummy){
dummy.wait();
}
System.out.println("第二个进程被唤醒了");
}
catch(Exception e){
}
}//end run()
}//end class FirstThread
class SecondThread extends Thread {
Object dummy;
public SecondThread(Object s){
dummy=s;
System.out.println("第二个进程被执行了");
}
public void run(){
try{
System.out.println("第二个进程已经开始了");
Thread.sleep(5000);
synchronized(dummy){
dummy.notifyAll();
}
}
catch(Exception e){
}//end run()
}//end class SecondThread
11.11
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class Animation extends Applet implements Runnable{ private Thread animation=null;
private final int delay=50;
private final int imageNum=5;
private Image[]images=new Image[imageNum];
public void run(){}
public void start(){
animation=new Thread(this);
if(animation!=null){
animation.start();
}//end public void start()
public void paint(Graphics g){
for(int i=0;i<imageNum;i++){
g.drawImage(images[i],25,25,100,100,this);
try{
Thread.sleep(delay);
}catch(InterruptedException e){}
}//end for
}//end paint(Graphics g)
public void update(Graphics g){
paint(g);
}//end update(Graphics g)
//Construct the applet
public Animation() {
}//end public Animation()
//Initialize the applet
public void init() {
jbInit();
}
catch (Exception e) {
e.printStackTrace();
}
}//end public void init()
//Component initialization
private void jbInit() throws Exception {
this.setSize(300,200);
for(int i=0;i<imageNum;i++){
images[i]=getImage(getCodeBase(),(i+1)+".jpg");
}
}//end private void jbInit()
}//end public class Animation
要在当前目录下存放5个.jpg的图片,然后才会有图片显示。

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK"> <title>
HTML Test Page
</head>
<body>
Animation will appear below in a Java enabled browser.<br> <applet
codebase = "."
code = "Animation.class"
name = "TestApplet"
width = "400"
height = "300"
hspace = "0"
vspace = "0"
align = "middle"
>
</applet>
</body>
</html>。

相关文档
最新文档