java 实验八 多线程 实验报告Word下载.docx
《java 实验八 多线程 实验报告Word下载.docx》由会员分享,可在线阅读,更多相关《java 实验八 多线程 实验报告Word下载.docx(25页珍藏版)》请在冰豆网上搜索。
A)程序不能编译,产生异常。
B)程序能编译运行,但没有任何结果输出。
C)程序能编译运行,输出结果:
OK.。
D)上面说法都不对。
5.为什么处于激活状态的线程可能不是当前正在执行的线程?
(BCD)
(备注:
激活(unblock):
如果阻塞线程的事件发生,则该线程被激活并进入就绪队列。
)
A)因为已经执行完run()方法。
B)线程正在等待键盘输入。
C)该线程调用了wait()方法。
D)该线程正在休眠状态。
2.下面是一个多线程的程序:
publicclassSimpleThreadextendsThread{
publicSimpleThread(Stringstr){
super(str);
}
publicvoidrun(){
for(inti=0;
i<
10;
i++){
System.out.println(i+"
"
+getName());
try{
sleep((long)(Math.random()*1000));
}catch(InterruptedExceptione){}
System.out.println("
DONE!
publicclassTwoThreadsTest{
publicstaticvoidmain(String[]args){
newSimpleThread("
Jamaica"
).start();
Fiji"
(1)输入该程序并运行之,体会多线程的程序的编写方法。
输入该程序后执行结果截图如下:
(2)将该程序该为通过实现Runnable接口的方式实现多线程。
改为Runnable后程序代码如下:
packagezi;
publicclassEx8_2_2{
publicstaticvoidmain(Stringargs[])
{
Movemove=newMove();
move.test1.start();
move.test2.start();
classMoveimplementsRunnable
{
Threadtest1,test2;
Move()
test1=newThread(this);
test1.setName("
test2=newThread(this);
test2.setName("
publicvoidrun()
if(Thread.currentThread()==test1)
{
for(inti=1;
i<
=10;
i++)
{
System.out.println(test1.getName());
}
else
=5;
System.out.println(test2.getName());
运行结果截图如下:
3,课本270页课后习题第4题。
下面给出一个范例(只供参考):
(1)这个程序运行就是一个进程,根据要求要设计三个线程,首先给出一个协助三个线程通信的类:
(2)接下来根据要求设计A线程和B线程,因为两个线程功能相同,所以可以是同一个类的不同实例对象,设计该类如下:
我们可以看到,基本设计方法与书本并无区别,同样为了协调三个线程之间通信,我们使用了一个通信类,根据规范操作,每个线程对通信类实例进行操作时,需要进行同步,就是
synchronized(){//获得锁旗标
具体执行就是根据题意,调用wait()等待,注意wait()跟sleep()是有区别的,前者会自动释放CPU和同步锁旗标,而后者会释放CPU,但不会释放同步锁旗标,在这里,由于三个线程都使用了同一个同步对象,因此,需要使用wait()(当然大家也可以不使用通信对象来完成这个题目)。
(请大家详细看课本262页的解析)
Wait()之后,就将自己至于就绪等待队列,然后
是唤醒其他线程,很明显在当前进程中,一共才三个线程,A和B进入了wait状态,它们唤醒的就只有C了,于是C出场。
(3)关于C的类设计结构基本跟上面A、B类一样,就是在run方法里面根据要求编写,首先就是sleep一段时间,参数单位是毫秒,然后调用notifyall让A和B继续运行,A和B运行结束之后,自然会回到C运行,这时如何按题意来判断其他线程都已结束呢?
我们可以再
.wait();
一次,作用是C放弃当前CPY与锁旗标,让其他线程先运行完毕,这个时候如果C线程重新开始回到CPU执行,意味着没有其他线程了,也就是可以判断AB已经执行完了,于是自己也愉快的结束运行。
关键代码见下:
(4)测试类一如既往与书本一样,如下:
该题代码如下:
publicclassEx8_3{
ThreadA=newThread("
A"
){
publicvoidrun(){
Wait("
};
ThreadB=newThread("
B"
ThreadC=newThread("
C"
while(true){
if(!
A.isAlive()&
&
!
B.isAlive())
return;
try{
Thread.sleep(2000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
notifyall();
publicsynchronizedvoidWait(Stringname){
System.out.println(name+"
start"
try{
wait();
}catch(InterruptedExceptione){
e.printStackTrace();
end"
publicsynchronizedvoidnotifyall(){
notifyAll();
publicstaticvoidmain(Stringargs[]){
Ex8_3test=newEx8_3();
//A、B两线程一起输入start和输出end,不过中间有C让线程休眠2秒,没法全部一次性输出,
//之后再唤醒,让AB继续输出下半部分end
test.A.start();
test.B.start();
test.C.start();
其运行结果截图如下:
4,课本270页课后习题第5题,记得要实现线程互斥(同步)。
这个跟书本例题差不多的设计方式,记得是生产者与消费者模型,书本展示了两种实现方式,建议采用第二种比较规范(256页例8-9),这里纯模仿就可以,具体不细说了,大家看说,纯模仿,看结果。
依题意,该题代码如下:
importjava.util.Scanner;
classData{
StringstudentId;
Stringname;
booleanavailable=false;
//判断是读是写
Scannerin=newScanner(System.in);
//定义一个输入对象
publicsynchronizedvoidread()
if(available)
try
wait();
catch(Exceptione)
System.out.printf("
请输入学号:
"
try
studentId=in.next();
catch(Exceptione)
输入学号出错!
请输入姓名:
name=in.next();
输入姓名出错!
System.out.println();
available=true;
notify();
publicsynchronizedvoidwrite()
if(!
available)
{
System.out.println("
输出学生学号:
+studentId+"
姓名:
+name+"
\n"
available=false;
//Read类
classReadextendsThread{
Datad1=null;
publicRead(Datad){
this.d1=d;
publicvoidrun(){
while(true)
d1.read();
//Write类
classWriteextendsThread{
Datad2=null;
publicWrite(Datad)
this.d2=d;
d2.write();
publicclassEx8_4{
publicstaticvoidmain(String[]args){
Datadata=newData();
newRead(data).start();
newWrite(data).start();
执行结果截图如下:
5,课本270页课后习题第10题。
这一题主要运用wait()和notify()来同步,这个程序本身是一个进程,里面根据题意一共设计只有两个线程,一个wait,然后notify自然就是启动另一个线程,如此交替运行,实现侦听。
注意这两个线程功能相同,所以可以是同一个类的不同对象,这个类如下(参考,大家可以自己编写):
classMyThreadextendsThread{
StringBuffersendString;
StringBufferrecvString;
MyThread(Stringname,StringBuffersendString,StringBufferrecvString){
this.name=name;
this.sendString=sendString;
this.recvString=recvString;
@Override
//循环100次,每次循环都sleep一段随机事件,然后收发消息
for(inti=0;
100;
inttime=(int)(Math.random()*100);
sleep(time);
catch(Exceptione){
e.printStackTrace();
sendMsg();
recvMsg();
//发送消息
publicvoidsendMsg(){
synchronized(sendString){
while(sendString.length()>
0){
sendString.wait();
doublecontent=Math.random();
sendString.append(name+content);
System.out.println(name+"
send"
+content);
sendString.notify();
//接收消息
publicvoidrecvMsg(){
synchronized(recvString){
while(recvString.length()==0){
recvString.wait();
recv"
+recvString);
recvString.delete(0,recvString.length());
recvString.notify();
请详细分析看懂以上代码,然后自己修改适合自己的类,最后编写测试类,实现题意功能,运行结果见下:
我选择了模拟银行账户类,代码如下:
classMbankCompex{//模拟银行账户类
privatestaticintsum=2000;
publicsynchronizedstaticvoidtake(intk){//限定take为同步方法
inttemp=sum;
temp-=k;
Thread.sleep((int)(100*Math.random()));
catch(InterruptedExceptione){}
sum=temp;
System.out.println(Thread.currentThread()+"
sum="
+sum);
classUserGetMoneyextendsThread{//模拟用户取款的线程类
for(inti=1;
=4;
i++){
MbankCompex.take(100);
publicclassEx8_5{//调用线程的主类
publicstaticvoidmain(String[]args){
UserGetMoneyu1=newUserGetMoney();
UserGetMoneyu2=newUserGetMoney();
u1.start();
u2.start();
6【选做】,编写一个应用程序,除了主线程外,还有两个线程:
first和second。
first负责模拟一个红色的按钮从坐标(10,60)运动到(100,60);
second负责模拟一个绿色的按钮从坐标(100,60)运动到(200,60),输出模拟过程。
(要结合第9章的画图知识)
依题意,代码如下:
importjavax.swing.*;
importjava.awt.*;
publicclassEx8_6extendsJFrameimplementsRunnable{
Threadfirst=newThread(this,"
1"
ThreadSecond=newThread(this,"
2"
JButtongreen=newJButton();
JButtonred=newJButton();
JLabellgreen=newJLabel("
100,60"
JLabellred=newJLabel("
10,60"
intx=10,y=60,x1=100;
Ex8_6(){
setLayout(null);
green.setBackground(Color.green);
green.setBounds(100,60,30,20);
red.setBackground(Color.red);
red.setBounds(10,60,30,20);
lred.setBounds(10,50,50,10);
lgreen.setBounds(100,80,50,10);
add(green);
add(red);
add(lgreen);
add(lred);
setSize(300,250);
setVisible(true);
first.start();
Stringcr=Thread.currentThread().getName();
if(cr.equals("
)){
while(x<
100){
try{
x+=10;
red.setLocation(x,y);
lred.setLocation(x,y-10);
lred.setText(x+"
60"
Thread.sleep(200);
}catch(Exceptione){}
Second.start();
else{
while(x1<
200){
x1+=10;
green.setLocation(x1,y);
lgreen.setLocation(x1,y+20);
lgreen.setText(x1+"
publicstaticvoidmain(Stringargs[]){
newEx8_6();
其运行结果如下所示:
该程序UML图截图如下:
7【选做】,广深和谐号每列火车可售出800张票,现设有4个人工售票口以及10台自动售票机,假设每次操作售出都是一张票,人工售票口平均每10秒(这个数字是为了方便调试测试,与现实有差距)售出一张,自动售票机平均20秒售出一张,请开设14个子线程模拟售出该800张票(模拟过程输出结果的后50行截图即可),并给出售出总时间,并按售出票数从多到少将各窗口排序输出,并给出各窗口售票张数。
提示:
(1),请参考书上相似的例子,基本模型与该例子相似,如题目有不完善处,请依据该模型自行完善
(2),要通过命名标记人工售票窗1号-4号,自动售票机1号-10号,以方便区别。
8【选做】在某KFC餐厅中一共有6个服务窗口,以供应奥尔良烤翅为例,1号至6号窗口每10秒(这个数字是为了方便调试测试,与现实有差距)分别卖出的对数分别是{2,1,1,3,2,1},而制作奥尔良烤翅的师傅有两名,一名每1分钟制作30对,一名每30秒制作20对。
请问卖出300对烤翅需要多长时间?
两名师傅分别生产多少对?
6个窗口分别卖出多少对?
请模拟这一过程(最后50对截图即可)。
提示:
(1)请参考书上相似的例子,基本模型相似,如题目有不完善处,请依据该模型自行完善;
(2)要通过命名标记各不同的生产者与消费者,记得生产者与消费者要同步。
(3)每10秒卖出一对,可以采用sleep,让线程等待来模拟。
测试时可以将所有数值等同缩小,其间逻辑关系不变,这样就不用等待很长时间久可以模拟。
如10秒统一换成1秒,那1分钟就是6秒,30秒就是3秒,如此类推。
测试完毕后将数据调为要求数据即可。
(4)注意当300对买完后,需要中止各个子线程并输出结果。
9【选做】.编写一个堆栈类MyStack,类中定义含5个元素的整型数组,并定义了两个同步(synchronized)方法:
入栈操作方法push(intk),用来向堆栈中压入一个整数;
出栈操作方法intpop(),用来从栈顶弹出一个整数。
方法push和pop中,通过wait()方法和notify()方法协调压入和弹出操作,