资源描述
实战java程序设计课后答案
第十一章 多线程技术
一、 选择题
1. A
2. C
3. A,D
4. C
5. D
二、 简答题
1.简述程序、进程和线程的联系和区别。
答:程序(Program):是一个指令的集合。程序不能独立执行,只有被加载到内存中,系统为它分配资源后才能执行。
进程(Process):如上所述,一个执行中的程序称为进程。
进程是系统分配资源的独立单位,每个进程占有特定的地址空间。
程序是进程的静态文本描述,进程是程序在系统内顺序执行的动态活动。
线程(Thread):是进程的“单一的连续控制流程“。
线程是CPU调度和分配的基本单位,是比进程更小的能独立运行的基本单位,也被称为轻量级的进程。线程不能独立存在,必须依附于某个进程。一个进程可以包括多个并行的线程,一个线程肯定属于一个进程。Java虚拟机允许应用程序并发地执行多个线程。
举例:如一个车间是一个程序,一个正在进行生产任务的车间是一个进程,车间内每个从事不同工作的工人是一个线程。
2. 创建线程的两种方式分别是什么?各有什么优缺点。
1. 方式1:继承java.lang.Thread类,并覆盖run() 方法。
优势:编写简单;
劣势:无法继承其它父类
2. 方式2:实现java.lang.Runnable接口,并实现run()方法。
优势:可继承其它类,多线程可共享同一个Thread对象;
劣势:编程方式稍微复杂,如需访问当前线程,需调用Thread.currentThread()方法
3. sleep、yield、join方法的区别
答:sleep():在指定时间内让线程暂停执行,进入阻塞状态。
在指定时间到达后进入就绪状态。线程调用sleep()方法时,释放CPU当不释放对象锁(如果持有某个对象的锁的话)。
join(): 当前线程等待调用此方法的线程执行结束再继续执行。如:在main方法中调用t.join(),那main方法在此时进入阻塞状态,一直等t线程执行完,main方法再恢复到就绪状态,准备继续执行。
yield(): 调用该方法的线程暂停一下,回到就绪状态。所以调用该方法的线程很可能进入就绪状态后马上又被执行。
4.synchonized修饰的语句块,如下面的代码,是表示该代码运行时必须获得account对象锁,如果没有获得,会有什么情况发生?
Synchronized(account){
If(account.money-drawingNum<0){
Return;
}
}
答:If判断失效,账户出现负数;
5.Java中实现线程通信的三个方法及其作用?
答:wait(),notify(),notifyAll()不属于Thread类,而是属于Object类,也就是说每个对象都有wait(),notify(),notifyAll()的功能。因为每个对像都有锁,锁是每个对像的基础,而wait(),notify(),notifyAll()都是跟锁有关的方法。
三个方法的作用分别是:
wait:导致当前线程等待,进入阻塞状态,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。该线程等到重新获得对监视器的所有权后才能继续执行.
notify:唤醒在此对象监视器(对象锁)上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。此方法只应由作为此对象监视器的所有者的线程来调用.
notifyAll: 唤醒在此对象监视器(对象锁)上等待的所有线程。
三、 编码题
1. 设计一个多线程的程序如下:设计一个火车售票模拟程序。假如火车站要有100张火车票要卖出,现在有5个售票点同时售票,用5个线程模拟这5个售票点的售票情况。
线程类
public class SaleTicket implements Runnable {
public int total = 100;// 总票数
public int count = 0;// 票号
public void run() {
while (total > 0) {
synchronized (this) {
if (total > 0) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++; // 票号++
total--;// 总数减少
// 输出当前的售票窗口和票号
System.out.println(Thread.currentThread().getName()
+ "\t当前票号:" + count);
}
}
}
}
}
测试类
public class Test {
public static void main(String[] args) {
// 创建线程类对象
SaleTicket st = new SaleTicket();
// 启动5次线程
for (int i = 1; i <= 5; i++) {
new Thread(st, "售票点" + i).start();
}
}
}
2. 编写两个线程,一个线程打印1-52的整数,另一个线程打印字母A-Z。打印顺序为12A34B56C….5152Z。即按照整数和字母的顺序从小到大打印,并且每打印两个整数后,打印一个字母,交替循环打印,直到打印到整数52和字母Z结束。
要求:
1) 编写打印类Printer,声明私有属性index,初始值为1,用来表示是第几次打印。
2) 在打印类Printer中编写打印数字的方法print(int i),3的倍数就使用wait()方法等待,否则就输出i,使用notifyAll()进行唤醒其它线程。
3) 在打印类Printer中编写打印字母的方法print(char c),不是3的倍数就等待,否则就打印输出字母c,使用notifyAll()进行唤醒其它线程。
4) 编写打印数字的线程NumberPrinter继承Thread类,声明私有属性private Printer p;在构造方法中进行赋值,实现父类的run方法,调用Printer类中的输出数字的方法。
5) 编写打印字母的线程LetterPrinter继承Thread类,声明私有属性private Printer p;在构造方法中进行赋值,实现父类的run方法,调用Printer类中的输出字母的方法。
6) 编写测试类Test,创建打印类对象,创建两个线程类对象,启动线程。
打印类(共享资源)
public class Printer {
private int index=1;//设为1,方便计算3的倍数
//打印数字的方法,每打印两个数字,等待打印一个字母
public synchronized void print(int i){
while(index%3==0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print(""+i);
index++;
notifyAll();
}
//打印字母,每打印一个字母,等待打印两个数字
public synchronized void print(char c){
while(index%3!=0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print(""+c);
index++;
notifyAll();
}
}
打印字母线程
public class LetterPrinter extends Thread {
private Printer p;
public LetterPrinter(Printer p){
this.p=p;
}
public void run(){
for(char c='A';c<='Z';c++){
p.print(c);
}
}
}
打印数字线程
public class NumberPrinter extends Thread {
private Printer p;
public NumberPrinter(Printer p){
this.p=p;
}
public void run(){
for(int i=1;i<=52;i++){
p.print(i);
}
}
}
测试类
public class Test {
public static void main(String[] args) {
Printer p=new Printer(); //创建打印机对象
Thread t1=new NumberPrinter(p); //创建线程对象
Thread t2=new LetterPrinter(p); //创建线程对象
t1.start(); //启动线程
t2.start(); //启动线程
}
}
3.编写多线程程序,模拟多个人通过一个山洞的模拟。这个山洞每次只能通过一个人,每个人通过山洞的时间为5秒,有10个人同时准备过此山洞,显示每次通过山洞人的姓名和顺序。
public class MulThreadTest{
public static void main(String[] args) {
//创建一个山洞(0.5分)
Tunnel tul = new Tunnel();
//创建十个过山洞线程(1.0分)
Thread p1 = new Thread(tul,"p1"); Thread p2 = new Thread(tul,"p2");
Thread p3 = new Thread(tul,"p3"); Thread p4 = new Thread(tul,"p4");
Thread p5 = new Thread(tul,"p5"); Thread p6 = new Thread(tul,"p6");
Thread p7 = new Thread(tul,"p7"); Thread p8 = new Thread(tul,"p8");
Thread p9 = new Thread(tul,"p9"); Thread p10 = new Thread(tul,"p10");
//启动十个线程0.5分
p1.start(); p2.start(); p3.start(); p4.start();
p5.start(); p6.start();
p7.start(); p8.start();
p9.start(); p10.start();
}
}
class Tunnel implements Runnable{
private int crossedNum = 0;//初始人数0.5分
public void run(){//1分
cross();
}
public synchronized void cross(){
try { //每个人通过山洞的时间为5秒(1分)
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//人数计数(0.5分)
crossedNum++;
//显示一下每次通过山洞人的姓名(1分)
System.out.println(Thread.currentThread().getName()+
"通过了山洞,这是第"+crossedNum+"个用户");
}
}
5
展开阅读全文