实验2线程与同步解答.doc
word实验二 线程与同步一、实验目的1 理解线程的根本概念2 掌握Java中线程类与Runnable接口的应用3 掌握控制线程根本方法4 掌握Java中线程的同步与互斥的实现二、实验容1 验证课堂练习的结果,下面是课堂练习的容:(1) 编写一个程序,能够根据用户的输入的数值生成相应数目的线程,每个线程运行1秒后完毕。(2) 编写一个程序,能够生成n个线程,每个线程每隔1秒打印自己的序号,当用户输入m后第m个线程完毕。(3) 编写一个程序,能够生成n个线程,每个线程打印自己的序号后完毕,但要求最终的打印的结果为n,n1,1。2 将第三题改写为能够按照任意顺序完毕。3 编写一个程序由假如干个类组成,该程序能够生成3个线程,其中2个线程向一个队列中写入数据,每次写入1个字节,1个线程从队列中读出数据,一次2个字节。要求读写交替运行,并注意数据的同步,而且队列要借助数组实现。三、实验步骤1 运行Eclipse,在其中新建一个Java工程JavaNetwork;2 创建package lab.lab2,并在其中创建一个Java类FirstThread并运行查看结果,其代码如下:package lab.lab2;import java.io.*;public class FirstThread extends Threadpublic static void main(String args) int n;try n=Integer.parseInt(new BufferedReader(new InputStreamReader(System.in).readLine();for (int i=0;i<n;i+)(new FirstThread().start(); catch (IOException e) e.printStackTrace();public void run()System.out.println("Thread started.");try Thread.sleep(1000); catch (InterruptedException e) e.printStackTrace();System.out.println("Thread ended.");运行该程序后,程序会等待用户的输入,如果用户输入:3结果将会是:Thread started.Thread started.Thread started.Thread ended.Thread ended.Thread ended.即程序会根据用户输入的数值来生成相应数目的线程,每个线程运行1秒后完毕。3 在package lab.lab2中创建一个Java类SecondThread并运行查看结果,其代码如下:package lab.lab2;import java.io.*;public class SecondThread extends Threadprivate int id;private boolean flag=true;private static SecondThread t;private static int n=5;public SecondThread(int id)this.id=id;public void stopThread()flag=false;public boolean getThreadState()return flag;public static void main(String args) int m;t=new SecondThreadn;for (int i=0;i<n;i+)(ti=new SecondThread(i).start();while(testThreads()try m=Integer.parseInt(new BufferedReader(new InputStreamReader(System.in).readLine();tm.stopThread(); catch (IOException e) e.printStackTrace();System.out.println("program ended.");public void run()System.out.println("Thread "+id+" started.");while (flag)try Thread.sleep(1000); catch (InterruptedException e) e.printStackTrace();System.out.println("Thread "+id+" ended.");private static boolean testThreads()boolean flag=false;for (int i=0;i<n;i+)flag|=ti.getThreadState();return flag;运行该程序后,屏幕将首先出现:Thread 0 started.Thread 1 started.Thread 2 started.Thread 3 started.Thread 4 started.然后等待用户输入,如果这时用户依次输入0、3、2、1、4,屏幕将依次出现0Thread 0 ended.3Thread 3 ended.2Thread 2 ended.1Thread 1 ended.4program ended.Thread 4 ended.即程序会根据用户输入的数值来完毕相应序号的线程,所有线程完毕后程序完毕。4 在package lab.lab2中创建一个Java类ThirdRunnable并运行查看结果,其代码如下:package lab.lab2;public class ThirdRunnable implements Runnableprivate int id;private static int stopid=-1;static int n=10;public ThirdRunnable(int id)this.id=id;public static void main(String args) for (int i=1;i<=n;i+)new Thread(new ThirdRunnable(i).start();stopid=n;public void run()System.out.println("Thread "+id+" started.");while (id!=stopid)Thread.yield();System.out.println("Thread "+id+" ended.");stopid-;运行该程序后,屏幕将出现:Thread 1 started.Thread 2 started.Thread 3 started.Thread 4 started.Thread 5 started.Thread 6 started.Thread 7 started.Thread 8 started.Thread 9 started.Thread 10 started.Thread 10 ended.Thread 9 ended.Thread 8 ended.Thread 7 ended.Thread 6 ended.Thread 5 ended.Thread 4 ended.Thread 3 ended.Thread 2 ended.Thread 1 ended.即程序会根据按照正序启动10个线程,然后逆序完毕线程。5 将ThirdRunnable类改写,使其能够按照任意顺序完毕;下面是就是改写后的结果。package lab.lab2;public class FourthRunnable implements Runnable/线程按照下面熟组元素的顺序依次完毕。private static int t=4,5,9,3,1,0,2,6,8,7;private int id;private static int stopid=0;public FourthRunnable(int id)this.id=id;public static void main(String args) for (int i=0;i<t.length;i+)(new Thread(new FourthRunnable(i).start();public void run()System.out.println("Thread "+id+" started.");try Thread.sleep(2000); catch (InterruptedException e) e.printStackTrace();while (id!=tstopid)Thread.yield();System.out.println("Thread "+id+" ended.");stopid+;6 编写代码实现实验容中的第3题。四、调试分析在调试线程程序的过程中,并干扰到其它应用程序的正常运行,后来经过仔细观察,发现是因为在线程的循环体当中没有调用sleep语句,从而导致线程不断地抢占CPU,从而影响其它程序的正常运行。五、实验结果按照指导书的步骤完成了第1题和第2题,同时编写程序完成了第3题,达到了所要求的实验结果。第3题的源代码如下:/环形队列package lab.lab2;public class DataQuque final int MAXLENGTH=10;byte data=new byteMAXLENGTH;int length;int startpos;int endpos;public int read()int b;if (length<2)return -1;else if(startpos=MAXLENGTH-2)b=dataMAXLENGTH-2;b=b<<8;b|=dataMAXLENGTH-1;startpos=0;length-=2;return b;else if(startpos=MAXLENGTH-1)b=dataMAXLENGTH-1;b=b<<8;b|=data0;length-=2;startpos=1;return b;elseb=datastartpos;b=b<<8;b|=datastartpos+1;length-=2;startpos+=2;return b;public boolean write(int b)if (length=MAXLENGTH)return false;else if(endpos=MAXLENGTH-1)dataMAXLENGTH-1=(byte)b;endpos=0;length+;return true;elsedataendpos+=(byte)b;length+;return true;/读取线程package lab.lab2;public class DataReader extends Thread boolean flag = true;DataQuque dq;int id;public DataReader(DataQuque dq, int id) this.dq = dq;this.id = id;public void run() int b;try Thread.sleep(1000*id); catch (InterruptedException e) e.printStackTrace();while (flag) synchronized (dq) if (b = dq.read() = -1)try dq.wait(); catch (InterruptedException e1) e1.printStackTrace();else System.out.println("read:" + b+" dq:"+dq.length);System.out.flush();dq.notifyAll();public void stopThread() flag = false;/写入线程package lab.lab2;public class DataWriter extends Threadboolean flag = true;DataQuque dq;int id;public DataWriter(DataQuque dq, int id) this.dq = dq;this.id = id;public void run() try Thread.sleep(1000*id); catch (InterruptedException e) e.printStackTrace();while (flag) synchronized (dq) if (!dq.write(id)try dq.wait(); catch (InterruptedException e) e.printStackTrace();elsedq.notifyAll();System.out.println("write:"+id+" dq:"+dq.length);System.out.flush();public void stopThread() flag = false;/控制类程序入口package lab.lab2;public class DataController public static void main(String args) DataQuque dq=new DataQuque();DataWriter dw1=new DataWriter(dq,1);DataWriter dw2=new DataWriter(dq,2);DataReader dr=new DataReader(dq,3);dw1.start();dw2.start();dr.start();try Thread.sleep(5000); catch (InterruptedException e) e.printStackTrace();dw1.stopThread();dw2.stopThread();dr.stopThread();六、实验总结通过本次实验,熟悉了Java中线程的创建有二个方法,特别是runnable接口的练习。需要在创建线程时候的参数是 runnable 类的对象。七、课后练习1 编写一个多线程程序,该程序主要完成以下工作:1生成两个发送线程s1,s2和一个接收线程r;2接收线程r每接收到M个来自于s1的数据和N个s2的数据后将它们分别求平均值后输出;3这样的接收过程总共进展3次。/接收线程package thread.control;import java.util.*;public class DataReciever extends ThreadArrayList datalist=new ArrayList();final int MAX=10;/最多只能有10个发送线程int datanum=new intMAX; /每个发送者每次能够发送的数据数int datalength=new intMAX;/每个发送者能够发送的数据总数int datacount=new intMAX; /每个发送者目前已纪发送的数据数int average=new intMAX;int senderId;int size;int total;volatile int count;public DataReciever()public int connect(int datasize,int maxlength)datanumsenderId=datasize;datalengthsenderId=maxlength;total+=maxlength;size+=datasize;int data=new intdatasize;/该发送线程的数据存储数组datalist.add(data);return senderId+;public void run()int printcount=0;int tempcount;while(true)tempcount=count;/count在运行中有可能会被接收线程改变,所以这里将它赋值给一个临时变量,以防止因它在运行过程中被改变而造成程序产生错误。if (tempcount%size=0)&& (tempcount>0) if (printcount!=tempcount)printcount=tempcount;/注意位置printResult();resetSenders();if (tempcount>=total) break;public boolean setData(int id,int data)/新增数据if (datacountid=datanumid)return false;addData(id,data);return true;private void addData(int id,int data)int temp=(int)datalist.get(id);tempdatacountid=data;datacountid+;count+;private void printResult()/打印结果for (int i=0;i<senderId;i+)int data=(int )datalist.get(i);System.out.println("nn Data form sender "+i+" : ");for (int j=0;j<datanumi;j+)System.out.print(dataj+" ");averagei+=dataj;averagei/=datanumi;System.out.println("n Average : "+averagei);private void resetSenders()/清空数据存储数组,准备接收下一组数据。for (int i=0;i<senderId;i+)datacounti=0;/发送线程package thread.control;import java.util.Random;public class DataSender extends ThreadDataReciever dr;int id;int datasize; /求平均所需的数据数M或Nint maxlength; /总共要发送的数据数M*TIMES或N*TIMESint count;public DataSender(DataReciever dr,int datasize,int maxlength) this.dr=dr;this.datasize=datasize;this.maxlength=maxlength;id=dr.connect(datasize,maxlength);/与接收线程连接,让接收线程为本发送线程建立数据传送通道标识,数据数组,每次发送的数据长度,所有数据数public void run() while (count < maxlength) /数据超过最大数如此完毕线程int data = 0xFF&generateData();/随机产生一个数据while (!dr.setData(id, data) /发送数据Thread.yield();System.out.print(""+id+".<"+data+">.");count+;private int generateData() Random r=new java.util.Random();return r.nextInt();/控制类(产生两个发送线程和一个接收线程。)package thread.control;public class DataMain public static void main(String args) final int TIMES=4;final int M=3,N=5;DataSender s1,s2;DataReciever r=new DataReciever();s1=new DataSender(r,M,M*TIMES);s2=new DataSender(r,N,N*TIMES);r.start();s1.start();s2.start();2 编写一个多线程程序,模拟多个售票点联网出售火车票的场景,假设车票有10,购票人有20人,售票点有3个,要求最终能够输出每车票的票号、售出地点、乘客。/乘客类package lab.lab2.ex2;public class Person public int personid;public String name;public Person(int personid)this.personid=personid;/火车票类package lab.lab2.ex2;public class Ticket public int ticketno;public String description;public Ticket(int ticketno)this.ticketno=ticketno;/售票点类package lab.lab2.ex2;import java.util.*;public class Position extends Threadint positionid;/售票点标识ArrayList<Person> personlist;/参加排队的乘客列表ArrayList<Ticket> ticketlist;/所有的火车票列表static boolean soldoutflag=false;/标记票是否售完public Position(int positionid,ArrayList<Ticket> ticketlist)this.positionid=positionid;this.ticketlist=ticketlist;personlist=new ArrayList<Person>();public void addPerson(Person p)/增加一个人排队personlist.add(p);public boolean sellTicket(Person p)/售票synchronized(ticketlist)if (soldoutflag) return false;Iterator it = ticketlist.iterator();Ticket t=null;if (it.hasNext()t = (Ticket) it.next();else System.out.println("Ticket is sold out.");soldoutflag=true;return false;if (t != null) System.out.println("Ticket " + t.ticketno + " is sold to person "+p.personid+" at position "+positionid+".");it.remove(); return true;public void run()Iterator it=personlist.iterator();Person p;Random rnd = new Random(); while (it.hasNext()/按排队顺序售票p=(Person)it.next();if(!sellTicket(p)break;it.remove();try sleep(Math.abs(rnd.nextInt()%4000); /随机产生的每次售票过程所需的时间 catch (InterruptedException e) e.printStackTrace();/控制类package lab.lab2.ex2;import java.util.*;public class TicketController public static void main(String args) int i;ArrayList<Ticket> ticketlist=new ArrayList<Ticket>();ArrayList<Person> personlist=new ArrayList<Person>();Ticket t;Position pos=new Position3;Person p;for (i=0;i<10;i+)t=new Ticket(i);ticketlist.add(t);for (i=0;i<3;i+)posi=new Position(i,ticketlist);for (i=0;i<20;i+)/将20个乘客分散到3个售票点p=new Person(i);personlist.add(p);posi%3.addPerson(p);for (i=0;i<3;i+)posi.start();14 / 14