java 实验八 多线程 实验报告.docx
- 文档编号:3862888
- 上传时间:2022-11-26
- 格式:DOCX
- 页数:25
- 大小:286.79KB
java 实验八 多线程 实验报告.docx
《java 实验八 多线程 实验报告.docx》由会员分享,可在线阅读,更多相关《java 实验八 多线程 实验报告.docx(25页珍藏版)》请在冰豆网上搜索。
java实验八多线程实验报告
实验八多线程
实验目标:
(1)掌握使用Thread的子类创建线程;掌握实现Runable接口来实现多线程;
(2)掌握线程之间的数据共享;
(3)掌握线程之间的同步方法;
(4)掌握线程之间的通信方法。
实验任务:
1、选择答题(请将答案标成红色,如(AB)):
1.下面关于线程的说法正确的是(ABD)。
A)Java支持多线程机制。
B)一个线程创建并启动后,它将执行自己的run()方法,如果通过派生Thread类实现多线程,则需要在子类中重新定义run()方法,把需要执行的代码写run()方法中;如果通过实现Runnable接口实现多线程,则要编写run()方法的方法体。
C)要在程序中实现多线程,必须导入Thread类:
importjava.lang.Thread;
D)一个程序中的主类不是Thread的子类,该类也没有实现Runnable接口,则这个主类运行是不能控制主线程的休眠。
2.如果程序中创建了两个线程,一个的优先级是Thread.MAX_PRIORITY,另一个的优先级是正常的默认优先级,下列陈述哪个是对的?
(A)
A)正常优先级的线程不运行,直到拥有最高优先级的线程停止运行。
B)即使拥有最高优先级的线程结束运行,正常优先级的线程也不会运行。
C)正常优先级的线程优先运行。
D)上述说法都不对。
3.下面哪个是Runnable接口中的抽象方法(D)?
A)startB)stopC)yieldD)run
4.编译下面的程序,得到的结果是(C)。
publicclassAimplementsRunnable{
publicvoidrun(){
System.out.println("OK.");
}
publicstaticvoidmain(String[]args){
ThreadTh=newThread(newA());
Th.start();
}
}
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!
"+getName());
}
}
publicclassTwoThreadsTest{
publicstaticvoidmain(String[]args){
newSimpleThread("Jamaica").start();
newSimpleThread("Fiji").start();
}
}
(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("Jamaica");
test2=newThread(this);
test2.setName("Fiji");
}
publicvoidrun()
{
if(Thread.currentThread()==test1)
{
for(inti=1;i<=10;i++)
{
System.out.println(test1.getName());
}
}
else
{
for(inti=1;i<=5;i++)
{
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)测试类一如既往与书本一样,如下:
该题代码如下:
packagezi;
publicclassEx8_3{
ThreadA=newThread("A"){
publicvoidrun(){
Wait("A");
}
};
ThreadB=newThread("B"){
publicvoidrun(){
Wait("B");
}
};
ThreadC=newThread("C"){
publicvoidrun(){
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();
}
System.out.println(name+"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),这里纯模仿就可以,具体不细说了,大家看说,纯模仿,看结果。
依题意,该题代码如下:
packagezi;
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)
{
System.out.println("输入学号出错!
");
}
System.out.printf("请输入姓名:
");
try
{
name=in.next();
}
catch(Exceptione)
{
System.out.println("输入姓名出错!
");
}
System.out.println();
available=true;
notify();
}
publicsynchronizedvoidwrite()
{
if(!
available)
try
{
wait();
}
catch(Exceptione)
{
}
System.out.println("输出学生学号:
"+studentId+"姓名:
"+name+"\n");
available=false;
notify();
}
}
//Read类
classReadextendsThread{
Datad1=null;
publicRead(Datad){
this.d1=d;
}
publicvoidrun(){
while(true)
{
d1.read();
}
}
}
//Write类
classWriteextendsThread{
Datad2=null;
publicWrite(Datad)
{
this.d2=d;
}
publicvoidrun()
{
while(true)
{
d2.write();
}
}
}
publicclassEx8_4{
publicstaticvoidmain(String[]args){
Datadata=newData();
newRead(data).start();
newWrite(data).start();
}
}
执行结果截图如下:
5,课本270页课后习题第10题。
这一题主要运用wait()和notify()来同步,这个程序本身是一个进程,里面根据题意一共设计只有两个线程,一个wait,然后notify自然就是启动另一个线程,如此交替运行,实现侦听。
注意这两个线程功能相同,所以可以是同一个类的不同对象,这个类如下(参考,大家可以自己编写):
classMyThreadextendsThread{
Stringname;
StringBuffersendString;
StringBufferrecvString;
MyThread(Stringname,StringBuffersendString,StringBufferrecvString){
this.name=name;
this.sendString=sendString;
this.recvString=recvString;
}
@Override
publicvoidrun(){
//循环100次,每次循环都sleep一段随机事件,然后收发消息
for(inti=0;i<100;i++){
inttime=(int)(Math.random()*100);
try{
sleep(time);
}
catch(Exceptione){
e.printStackTrace();
}
sendMsg();
recvMsg();
}
}
//发送消息
publicvoidsendMsg(){
synchronized(sendString){
while(sendString.length()>0){
try{
sendString.wait();
}
catch(Exceptione){
e.printStackTrace();
}
}
doublecontent=Math.random();
sendString.append(name+content);
System.out.println(name+"send"+content);
sendString.notify();
}
}
//接收消息
publicvoidrecvMsg(){
synchronized(recvString){
while(recvString.length()==0){
try{
recvString.wait();
}
catch(Exceptione){
e.printStackTrace();
}
}
System.out.println(name+"recv"+recvString);
recvString.delete(0,recvString.length());
recvString.notify();
}
}
}
请详细分析看懂以上代码,然后自己修改适合自己的类,最后编写测试类,实现题意功能,运行结果见下:
我选择了模拟银行账户类,代码如下:
packagezi;
classMbankCompex{//模拟银行账户类
privatestaticintsum=2000;
publicsynchronizedstaticvoidtake(intk){//限定take为同步方法
inttemp=sum;
temp-=k;
try{
Thread.sleep((int)(100*Math.random()));}
catch(InterruptedExceptione){}
sum=temp;
System.out.println(Thread.currentThread()+"sum="+sum);
}
}
classUserGetMoneyextendsThread{//模拟用户取款的线程类
publicvoidrun(){
for(inti=1;i<=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章的画图知识)
依题意,代码如下:
packagezi;
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();
}
publicvoidrun(){
Stringcr=Thread.currentThread().getName();
if(cr.equals("1")){
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){
try{
x1+=10;
green.setLocation(x1,y);
lgreen.setLocation(x1,y+20);
lgreen.setText(x1+",60");
Thread.sleep(200);
}catch(Exceptione){}
}
}
}
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()方法协调压入和弹出操作,
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- java 实验八 多线程 实验报告 实验 报告