Java程序设计教程(第2版)课后习题及答案11课后习题.docx
第11章课后习题参考答案1 .解释下列名词术语。进程、线程、状态、阻塞、优先级、同步、死锁、守护、线程安全进程:进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行 资源分配和调度的基本单位,是操作系统结构的基础。线程:线程是操作系统能够进行运算调度的最小单位,被包含在进程之中,是进程中的实际 运作单位。状态:状态用来表示线程所处的情况。线程状态有“新建”、“可运行”、“运行”、“阻 塞”、“死亡”等。阻塞:阻塞状态是指线程因为某种原因放弃CPU使用权,暂时停止运行。直到满足某个触 发条件又使线程进入就绪状态,才有机会转到运行状态。优先级:在操作系统中,线程可以划分优先级,线程优先级越高,获得CPU时间片的概率就 越大,但线程优先级的高低与线程的执行顺序并没有必然联系,优先级低的线程也有可能比优先级高 的线程先执行。同步:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作, 直到该线程完成操作,其他线程才能对该内存地址进行操作,而其他线程又处于等待状态。死锁:当两个线程被阻塞,每个线程在等待另一个线程时就发生死锁。守护:实际的意思是把一个线程标记为“守护线程”,就是当他是一个“后台线程” or “内 部线程”。线程安全:线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多 条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执 行,不会出现数据污染等意外情况。2 .线程有哪几种状态?答:线程在生命期中可能经历五种状态:新建(New)、就绪或者可运行(Ready or Runnable 运行(Running)、阻塞(Blocked)、死亡(Dead)。3 .简述Java线程调度的原理。答:所有的Java虚拟机都有一个线程调度器,用来确定那个时刻运行那个线程。主要包含 两种:抢占式线程调度器和协作式线程调度器。(1) .抢占式线程调度,每个线程可能会有自己的优先级,但是优先及并不意味着高优先级的 线程一定会被调度,而是由cup随机的选择,所谓抢占式的线程调度,就是说一个线程在执行自 己的任务时,虽然任务还没有执行完,但是cpu会迫使它暂停,让其它线程占有cpu的使用权。(2) .协作式线程调度,每个线程可以有自己的优先级,但优先级并不意味着高优先级的线程 一定会被最先调度,而是由cpu时机选择的,所谓协作式的线程调度,就是说一个线程在执行自 己的任务时,不允许被中途打断,一定等当前线程将任务执行完毕后才会释放对cpu的占有,其 它线程才可以抢占该cpu。4何谓线程同步?何谓线程间通信?答:同步就是使不同动作协调有序。线程同步指的是当程序中有多个线程,假设它们同时访 问同一个变量时,一些线程读数据,一些线程写数据,可能会出现数据读写错误,因此需要对这 些线程的数据访问操作进行控制,使之协调有序,避免数据访问操作出错。线程间通讯是多个线程在操作同一个资源时,多个线程之间不断切换执行时所发出的信号。5 .分析下面程序的执行结果。 class Sync extends Thread public synchronized void produceProduct() if (productCount < 20) productCount+;System.out.println(Thread.currentThread().getName() + ” :开始生产第” + productCount + “个产品”);notify();else 等待try wait(); catch (InterruptedException e) e.printStackTrace();消费产品public synchronized void consumeProduct() if (productCount > 0)System.out.println(Thread.currentThread().getName() + ”:开始消费第" + productCount + "个产品”);productCount-;notify();else /等待try (wait(); catch (InterruptedException e) e.printStackTrace();class Producer extends Thread 生产者private Clerk clerk;public Producer(Clerk clerk) this.clerk = clerk;)Overridepublic void run() System.out.println(getName() + ”:开始生产产品”);while (true) try ( Thread.sleep(lO); catch (InterruptedException e) e.printStackTrace();clerk. produceProduct();)class Consumer extends Thread 消费者private Clerk clerk;public Consumer(Clerk clerk) this.clerk = clerk;Overridepublic void run() System.out.println(getName() + ” :开始消费产品”);while (true) try (Thread.sleep(20); catch (InterruptedException e) e.printStackTrace();clerk.consumeProduct();public class ProductTest public static void main(String args) Clerk clerk = new Clerk();Producer pl = new Producer(clerk);pl.setName("生产者');Consumer cl = new Consumer(clerk); cLsetName(”消费者');Consumer c2 = new Consumer(clerk);c2.setName(”消费者 2)pl.startQ; cl.start(); c2.start();StringBuffer letter;public Sync(StringBuffer letter)this.letter = letter; public void run()synchronized(letter)for (int I = 1;I <= 100;+I)System.out.print(letter);System.out.printIn();char temp = letter.charAt(0);+temp;letter.setCharAt(0,temp);static void main(String args) publicStringBuffer sb=new StringBuffer(HAn);newnewnew )Sync(sb).start();Sync(sb).start();Sync(sb) .start ();答:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBBBBBccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc ccccccccccccccccccc由于使用synchronized关键字,程序的输出不会出现ABC字母的嵌套。6 .分析下面的程序是否会形成死锁,谈谈理由。package exercise;public class Exll 6public static void main(String args)DeadlockRisk dead =new DeadlockRisk();classMyThread4MyThread4 MyThread4MyThread4 tl.start () t2.start () t3.start () t4start()tl t2 t3 t4newnewnewnewMyThread4(dead,MyThread4(dead,MyThread4(dead,MyThread4(dead,MyThread4 extends Thread1,3,5,7,2);4);6);8);private DeadlockRisk dead;private int a, b;MyThread4(DeadlockRisk dead, int a, int b)this.dead = dead;this , aa;this.b = b;Override public void run() ( dead.read(); dead.write (a, b); ) class DeadlockRisk ( private static class Resource ( public int value;)private Resource resourceA = new Resource(); private Resource resourceB = new Resource ();public int read() ( synchronized (resourceA) (System, out .print In ("read () :“ + Thread. currentThread () . getName () + ”获取了 resourceA 的锁! ”);synchronized (resourceB) (System.out.printin("read():n + Thread.currentThread().getName() + ”获 取了 resourceB 的锁!“);return resourceB.value + resourceA.value; ) ) public void write(int a, int b) (synchronized (resourceB) (System.out.printin ("write () :n + Thread. currentThread () .getName () + ”获取了 resourceA 的锁! H);synchronized (resourceA) (System.out.printIn("write():“ + Thread.currentThread().getName() + ” 获取了 resourceB 的锁! ”); resourceA.value = a; resourceB.value = b; ) ) ) 答:会出现死锁,因为两个线程被阻塞了。7 .分析下面程序的功能。 package exercise; class Plate ( private int index=0; private char buffer=new char6; public synchronized void push (char c)while(index=buffer.length)try ( System.out .printIn (nThe plate is full, no room to put*'); this.wait(); ) catch(InterruptedException e) ( ) this , notify(); bufferindex=c; index+; ) public synchronized char pop () ( while(index=0) ( try (System.out.printIn(nThe plate is empty, no apple to eatn); this.wait(); ) catch(InterruptedException e) ( ) this ,notify(); index-; return bufferindex; ) ) class Father extends Thread ( Plate s; char ch=*;Father(Plate s) ( this s=s; ) public void run() ( while (true) ( s.push (ch); System.out.printIn (nI put an apple (n+(ch)+n) into the plate"); ) )class Child extends Thread ( Plate s;char ch; Child(Plate s) ( this . s=s; public void run()while (true) ( ch=s.pop(); System, out .printIn (nI get an apple ("+(ch)+”) from the plate*'); ) ) public class Exll_7 ( 一public static void main(String args) ( Plate s = new Plate (); Father f = new Father(s); Child c = new Child(s); f.start (); c.start ();) ) 答:产生两个线程,一个线程向堆栈插入字符2,另外一个线程从堆栈弹出字母。如果堆栈满了,或者空了, 给出相应的提示。8 .分析下面程序的功能。 package exercise; class NumberHolder (private int number; public synchronized void increase() if (0 != number) (try ( wait (); ) catch (InterruptedException e) (e.printStackTrace(); ) /能执行到这里说明已经被唤醒,并且number为0 number+;System.out.printIn(number); /通知在等待的线程 notify(); ) public synchronized void decrease() ( if (0 = number) ( try wait(); ) catch (InterruptedException e) (e.printStackTrace (); ) ) /能执行到这里说明已经被唤醒,并且number不为0 number-;System.out.printIn(number); notify ();class IncreaseThread extends Thread (private NumberHolder numberHolder;public IncreaseThread(NumberHolder numberHolder) this.numberHolder = numberHolder; )Override public void run() (for (int i = 0; i < 20; +i) (/进行一定的延时 try Thread.sleep(long) Math.random() * 1000); ) catch (InterruptedException e) e.printStackTrace ();)/进行增加操作 numberHolder.increase(); ) class DecreaseThread extends Thread (private NumberHolder numberHolder;public DecreaseThread(NumberHolder numberHolder) (this.numberHolder = numberHolder;)Override public void run() (for (int i = 0; i < 20; +i) (/进行一定的延时 try (Thread.sleep(long) Math.random() * 1000); catch (InterruptedException e) e.printStackTrace ();/进行减少操作 numberHolder.decrease(); ) ) )public class Exll_8public static void main(String args)NumberHolder numberHolder = new NumberHolder();Thread tl = new IncreaseThread(numberHolder);Thread t2 = new DecreaseThread(numberHolder);tl.start ();t2.start ();)答:产生两个线程IncreaseThread和DecreaseThread,他们随机增加和减少NumberHolder的变量 number,各进行20次操作后,退出循环。9 .项目练习:哲学家就餐问题,是1965年由Dijkstra提出的一种线程同步的问题。问题描述:一个圆桌前坐着5位哲学家,两个人中间有一只筷子,桌子中央有面条。哲学家 思考问题,当饿了的时候拿起左右两只筷子吃饭,必须拿到两只筷子才能吃饭。上述问题会产生 死锁的情况,当5个哲学家都拿起自己右手边的筷子,准备拿左手边的筷子时产生死锁现象。解决办法思路:(1)添加一个服务生,只有经过服务生同意之后才能拿筷子,服务生负责避免死锁发生。(2)每个哲学家必须确定自己左右手的筷子都可用的时候,才能同时拿起两只筷子进餐,吃 完之后同时放下两只筷子。(3)规定每个哲学家拿筷子时必须拿序号小的那只,这样最后一位未拿到筷子的哲学家只剩 下序号大的那只筷子,不能拿起,剩下的这只筷子就可以被其他哲学家使用,避免了死锁。这种 情况不能很好地利用资源。答:package exercise;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/*哲学家就餐问题*/class Proj3_02 static final Lock locks=new Lock5;static fbr (int i=0;i<locks.length;i+) locksi=new ReentrantLock();public static void main(String args) Philosopher philosopherO=new Philosopher,张三”,1000,0);Philosopher philosopher 1 =new Philosopher(“李四”,800,1);Philosopher philosopher2=new Philosopher(“王五”,400,2);Philosopher philosopher3=new Philosopher(”jhl”,2000,3);Philosopher philosopher4=new Philosopher("ghlcln,2000,4);philosopher0.start();philosopherl .start();philosopher2.start();philosophers.start();philosopher4.start();死循环,防止主线程退出导致进程关闭 while (true) static class Philosopher extends Thread private String name;private long time;private int num;public Philosopher(String name, long time, int num) this.name = name;this.time = time;this.num = num;)Overridepublic void run() while (true) System.out.println(num+”号哲学家"+name+”正在思考.模拟思考的过程 try Thread.slecp(time); catch (InterruptedException e) e.printStackTraceQ;)System.out.println(num+”号哲学家"+name+”饿了,想来吃饭.J);if (locksnum.tryLock() try (System.out.println(num+” 号哲学家”+name+”拿到了 左边的筷子! ”);if (locks(num+l)%5.tryLock()try System.out.println(num+n 号哲学家 "+name+” 拿到了 右 边的筷子!)System.out.println(num+n 号哲学家 "+name+” 开始吃饭! ”);模拟哲学家吃饭的过程Thread.sleep(time); catch (InterruptedException e) e.printStackTrace(); finally System.out.println(num+n 号哲学家 ”+name+” 放下了右边的筷子!)locks(num+ l)%5.unlock();else System.out.println(num+n 号哲学家 ”+name+” 没拿到了 右边 的筷子!被迫思考,) finally System.out.println(num+”号哲学家”+name+”放下了左边的筷子! ”);locksnum .unlock();)else System.out.println(num+”号哲学家”+name+”没拿到了左边的筷子!被 迫思考)System.out.println(num+”号哲学家”+name+”思考 ing.");/模拟思考过程try Thread.sleep(time); catch (InterruptedException e) e.printStackTraceQ;)10.项目练习:生产者消费者问题,准确地说是“生产者一消费者一仓储”模型,离开了仓 储,生产者消费者模型就显得没有说服力了。对于此模型,应该明确以下4点。(1)生产者仅仅在仓储未满时生产,仓满则停止生产。(2)消费者仅仅在仓储有产品时才能消费,仓空则等待。(3)当消费者发现仓储没产品可消费时会通知生产者生产。(4)生产者在生产出可消费产品时,应该通知等待的消费者去消费。此模型将要结合java.lang.Object的wait与notify> notifyAll方法来实现以上的需求。这是非 常重要的。答:package com.klvchen.java2;class Clerkprivate int productCount = 0;生产产品