Java实验报告(八)

一、实验目的(结出本次实验所涉及并要求掌握的知识点)

1、理解掌握线程的基本概念。

2、理解和掌握Java多线程结构和开发过程。

3、了解多线程运行机制和生命周期及状态迁移。

4、学会如何创建线程,掌握线程的调度策略,线程优先级和线程同步。

二、实验内容(结出实验内容具体描述)

1.设计一个线程类,它能输出 50 以内的奇数或偶数。用书中介绍的四种构造线程方法,创建两个线程对象,分别输出奇数和偶数。

2. 给定容量 1000 的 int 型数组,依次存储数据 0~999。下面代码采用多线 程技术计算其累加和。

3. 功能:实现多人竞争打电话,借助互斥机制,确保每个人的说话是连续 的。 class DianHuaTing{//此类对象仅提供多人打电话的共享资源 private final String dht="我是电话亭"; } class App{ public static void main (String[] args) { DianHuaTing d=new DianHuaTing(); String[] s1={"1","2","3"}; String[] s2={"A","B","C","D","E"}; String[] s3={"你好,","我也好,","大家都好!"}; Talkers t1=new Talkers(d,"张三",s1); Talkers t2=new Talkers(d,"李四",s2); Talkers t3=new Talkers(d,"王五",s3); t1.start (); t2.start (); t3.start (); } }

 4. 假设某个银行,它可以授受顾客的汇款,每做一次汇款,便可计算出汇 款的总额。现有两个顾客对同一个银行帐号操作,一个顾客分 3 次,每次 将 100 元钱存入,要求存入后将钱的总额输出。

5. 类 BufferArea 用于产生一个[1..100]的随机整数,并可取出此数。存数线 程类 ThreadPutNumber 将数存入缓冲区。读数线程类 ThreadPutNumber 从 缓冲区读取数并判断是否是素数。要求 main 线程最后结束。

三、算法描述及实验步骤(用适当的形式表达算法设计思想与算法实现步骤)

小实验一:设计一个线程类,它能输出 50 以内的奇数或偶数。用书中介绍的四种构造线程方法,创建两个线程对象,分别输出奇数和偶数。

分析:线程要包括三大点:1、要有汽车Thread类,2、要有线程体void run()  3、要有共享资源.start()

四种方法包括继承Thread类方法;实现Runnable接口方法;内部类方法;内部匿名类方法。四种方法的共同点都是要实现run()函数,然后通过main()实现多线程的同时进行,注意。main是特殊线程,最先启动,且只有当所有线程均结束后才能结束;千万不要重写start(),  不要主动调用run()。

由分析和图示可得代码

方法一:继承Thread类:

class MyThread extends Thread{

      private int n,m;

      public MyThread (String name,int n1,int m1) {

            super(name);n=n1;m=m1;

      }

      public void run() {

            for(int i=0;i<m;i++) {

                  if(i%2==n) {

                       System.out.print(i+"  ");

                  }

            }

            System.out.println(getName()+"结束   ");

      }

}



public class T1{

public static void main(String[] args) {

      System.out.print("Main 开始");

      MyThread m1=new MyThread("A",0,50);

      MyThread m2=new MyThread("B",1,50);

      m1.start();m2.start();

      System.out.println("当前共有"+Thread.activeCount()+"个线程 ");

      System.out.println("Main 结束");

}

}

方法二:实现Runnable接口:

class MyThread implements Runnable{

      private int n,m;

      public MyThread (int n1,int m1) {

            n=n1;m=m1;

      }

      @Override

      public void run() {

            // TODO 自动生成的方法存根

                       for(int i=0;i<m;i++) {

                  if(i%2==n) {

                       System.out.print(i+"  ");

                  }

            }

           System.out.println(Thread.currentThread().getName()+" 结束 ");

      }

}





public class T2 {

public static void main(String[] args) {

      System.out.print("Main 开始");

      MyThread m1,m2;Thread t1,t2;

      m1=new MyThread(0,50);

      m2=new MyThread(1,50);

      t1=new Thread(m1,"A");

      t2=new Thread(m2,"B");



      t1.start();t2.start();

      System.out.println("当前共有"+Thread.activeCount()+"个线程 ");

      System.out.println("Main 结束");

}

}

方法三:实现内部类:



class MyThread implements Runnable{

      private int n,m;Thread t;

      public MyThread(String name,int n1,int m1) {

             n=n1;m=m1;t=new Thread(this,name);

      }

      public void start() {

            t.start();

      }

      public void run() {

            for(int i=0;i<m;i++) {

      if(i%2==n) {

            System.out.print(i+"  ");

      }

}

           System.out.println(Thread.currentThread().getName()+" 结束 ");

      }

}





public class T3 {

public static void main(String[] args) {

      System.out.print("Main 开始");

      MyThread m1,m2;

      m1=new MyThread("A",0,50);

      m2=new MyThread("B",1,50);



      m1.start();m2.start();

      System.out.println("当前共有"+Thread.activeCount()+"个线程 ");

      System.out.println("Main 结束");

}

}

4.实现内部匿名类:

class T{

      class MyThread extends Thread{

            private int n,m;

            public MyThread(String name,int n1,int m1) {

                  super(name);  n=n1;  m=m1;

            }

            public void run() {

                  for(int i=0;i<m;i++) {

                       if(i%2==n) {

                             System.out.print(i+"   ");

                       }

                  }

                  System.out.println(getName()+"结束   ");

            }

      }

      public T(String name,int n1,int m1) {

            MyThread m=new MyThread(name,n1,m1);m.start();

      }

}



public class T4 {

public static void main(String[] args) {

      System.out.print("Main 开始"); T t1,t2;

      t1=new T("A",0,50);

      t2=new T("B",1,50);

      System.out.println("当前共有"+Thread.activeCount()+"个线程");

      System.out.print("Main 结束");

}

}

小实验2:给定容量 1000 的 int 型数组,依次存储数据 0~999。下面代码采用多线 程技术计算其累加和。

实验代码如下:

package jjk;



public class App {

    public static void main(String[] args) throws InterruptedException {

        final int max = 1000;

        int[] a = new int[max];

        int sum1 = 0, sum2 = 0, step = 10, num = 4;

        //每个线程每次至多累加 10 个数,共有 4 个线程

        for (int i = 0; i < max; i++) {//先计算出正确的累加和,以方便对比

            a[i] = i;

            sum1 = sum1 + a[i];

        }

        Pos p=new Pos(max,step);

        sum2=SumByThread(p, a,num,step);

        System.out.print("顺序:"+sum1+",并发:"+sum2);

    }



    public static int SumByThread(Pos p,int[] a,int num,int step) throws InterruptedException {



        MyThread[] t = new MyThread[4];

        for(int i=0;i<num;i++) {

            t[i] = new MyThread(p,step,a);

            t[i].start();

        }

        Thread.sleep(1000);

        return MyThread.sum;

    }

}



class Pos {

    private int max, step,pos;

    public Pos(int max,int step) {

        this.max = max;

        this.step = step;

        pos = 0;

    }



    public int getPos() {

        if(pos < max) {

            return pos;

        }

        return -1;

    }

    public void setPos(int pos) {

        this.pos = pos;

    }



}

class MyThread extends Thread {

    static int sum=0;

    private int step;

    private Pos p;

    private int[] a;

    private boolean flag;

    public MyThread(Pos p,int step,int[] a) {

        this.p = p;

        this.step = step;

        this.a = a;

        flag = false;

    }

    public void run() {

        while(true) {

            for(int i=0;i<step;i++) {

                synchronized (p) {

                        if(p.getPos() != -1) {

                            sum+=a[p.getPos()];

                            System.out.println(Thread.currentThread().getName()+" num:"+a[p.getPos()]+ " sum:"+sum);

                            p.setPos(p.getPos()+1);

                        } else {

                            return;

                        }



                }

            }

                try {

                    this.wait();

                    this.notifyAll();

                } catch (Exception e) {



                }

        }

    }

小实验3: 功能:实现多人竞争打电话,借助互斥机制,确保每个人的说话是连续 的。 class DianHuaTing{//此类对象仅提供多人打电话的共享资源 private final String dht="我是电话亭"; } class App{ public static void main (String[] args) { DianHuaTing d=new DianHuaTing(); String[] s1={"1","2","3"}; String[] s2={"A","B","C","D","E"}; String[] s3={"你好,","我也好,","大家都好!"}; Talkers t1=new Talkers(d,"张三",s1); Talkers t2=new Talkers(d,"李四",s2); Talkers t3=new Talkers(d,"王五",s3); t1.start (); t2.start (); t3.start (); } }

分析:本题的难点在于互斥机制,即实现每个人说的话连续,这就需要使用synchronized(),synchronize具有三个特性(1)、原子性:所谓原子性就是指一个操作或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。被synchronized修饰的类或对象的所有操作都是原子的,因为在执行操作之前必须先获得类或对象的锁,直到执行完才能释放。

(2)、可见性:可见性是指多个线程访问一个资源时,该资源的状态、值信息等对于其他线程都是可见的。 synchronized和volatile都具有可见性,其中synchronized对一个类或对象加锁时,一个线程如果要访问该类或对象必须先获得它的锁,而这个锁的状态对于其他任何线程都是可见的,并且在释放锁之前会将对变量的修改刷新到共享内存当中,保证资源变量的可见性。

(3)、有序性:有序性值程序执行的顺序按照代码先后执行。 synchronized和volatile都具有有序性,Java允许编译器和处理器对指令进行重排,但是指令重排并不会影响单线程的顺序,它影响的是多线程并发执行的顺序性。synchronized保证了每个时刻都只有一个线程访问同步代码块,也就确定了线程执行同步代码块是分先后顺序的,保证了有序性。

所以可以通过synchronize来实现互斥机制。

实验代码如下:

package e;

class DianHuaTing{//此类对象仅提供多人打电话的共享资源

       private final String dht="我是电话亭";

      }

class Talkers extends Thread{

      private DianHuaTing dianhuating;

      private String name;

      private String[] content;

      public Talkers(DianHuaTing f,String n,String[] s) {

            dianhuating=f;name=n;content=s;

      }

      public void run() {

            synchronized(dianhuating) {

                  System.out.print(name+" : ");

                  for(String x:content) System.out.print(" "+x);

                  System.out.println();

            }

      }

}





      class App{

       public static void main (String[] args) {

       DianHuaTing d=new DianHuaTing();

       String[] s1={"1","2","3"};

       String[] s2={"A","B","C","D","E"};

       String[] s3={"你好,","我也好,","大家都好!"};

       Talkers t1=new Talkers(d,"张三",s1);

       Talkers t2=new Talkers(d,"李四",s2);

       Talkers t3=new Talkers(d,"王五",s3);

       t1.start (); t2.start (); t3.start ();

       }

      }

小实验4:假设某个银行,它可以授受顾客的汇款,每做一次汇款,便可计算出汇 款的总额。现有两个顾客对同一个银行帐号操作,一个顾客分 3 次,每次 将 100 元钱存入,要求存入后将钱的总额输出。

分析: 实现这个程序,同样也要用到互斥机制,同时还要用到join(),以保证前面执行完成后再执行后面的内容而不造成混乱。

实验代码如下:

class Account{

      private String name;

      private double value;

      public String getName() {return name;}

      public double getValue() {return value;}

      public Account(String s,int d) {

            name=s;value=d;

      }

      public void putV(double m) {

            value+=m;

      }

      public void getV(double p) {

            value-=p;

      }

     

}

class Saver extends Thread{

      private Account a;

      private int i;

      public double c;

      public String nam;

      public Saver(Account a1,String n,int i,double c1) {

            a=a1;

            nam=n;

            this.i=i;

            c=c1;

      }

      public void run() {

            synchronized (a) {

                  try {

                       sleep(100);

                  } catch (InterruptedException e1) {

                       // TODO 自动生成的 catch 块

                       e1.printStackTrace();

                  }

                  System.out.println("银行当前余额为"+a.getValue()+","+nam+"第"+i+"次存入"+c+"元");

                  try {

                       sleep(100);

                  } catch (InterruptedException e1) {

                       // TODO 自动生成的 catch 块

                       e1.printStackTrace();

                  }

                  a.putV(c);

                  try {

                       sleep(100);

                  } catch (InterruptedException e) {

                        // TODO 自动生成的 catch 块

                       e.printStackTrace();

                  }

                  System.out.println("当前银行余额为:"+a.getValue());

                  try {

                       sleep(100);

                  } catch (InterruptedException e) {

                       // TODO 自动生成的 catch 块

                        e.printStackTrace();

                  }

            }

      }

}



class Fetcher extends Thread{

      private Account a;

      private int i;

      public double c;

      public String nam;

      public Fetcher(Account a1,String n,int i,double c1) {

            a=a1;

            nam=n;

            this.i=i;

            c=c1;

      }

      public void run() {

            synchronized (a) {

                  System.out.println("银行当前余额为"+a.getValue()+","+nam+"第"+i+"次取出"+c+"元");

                  a.getV(c);

                  System.out.println("当前银行余额为:"+a.getValue());

            }

      }

}

  

public class App {

public static void main(String[] args) throws InterruptedException {

      Account a=new Account("刘",1000);

      /*Saver s1=new Saver(a,"aa",1,100);s1.start();

      try {

            s1.join();

      } catch (InterruptedException e) {

            // TODO 自动生成的 catch 块

            e.printStackTrace();

      }

      Saver s2=new Saver(a,"bb",1,100);s2.start();

      try {

            s2.join();

      } catch (InterruptedException e) {

            // TODO 自动生成的 catch 块

            e.printStackTrace();

      }

      Saver s3=new Saver(a,"aa",2,100);s3.start();

      try {

            s3.join();

      } catch (InterruptedException e) {

            // TODO 自动生成的 catch 块

            e.printStackTrace();

      }

      Saver s4=new Saver(a,"bb",2,100);s4.start();

      try {

            s4.join();

      } catch (InterruptedException e) {

            // TODO 自动生成的 catch 块

            e.printStackTrace();

      } 

      Saver s5=new Saver(a,"aa",3,100);s5.start();

      Saver s6=new Saver(a,"bb",3,100);s6.start();*/

     

      //(new Fetcher(a,300)).start();

      Saver s1=new Saver(a,"aa",1,100);s1.start();

      s1.join();

      Saver s2=new Saver(a,"bb",1,100);s2.start();

      s2.join();

      Saver s3=new Saver(a,"aa",2,100);s3.start();

      s3.join();

      Saver s4=new Saver(a,"bb",2,100);s4.start();

      s4.join();

      Saver s5=new Saver(a,"aa",3,100);s5.start();

      s5.join();

      Saver s6=new Saver(a,"bb",3,100);s6.start();

}

} 

实验5:类 BufferArea 用于产生一个[1..100]的随机整数,并可取出此数。存数线 程类 ThreadPutNumber 将数存入缓冲区。读数线程类 ThreadPutNumber 从 缓冲区读取数并判断是否是素数。要求 main 线程最后结束。

分析: 这个程序类似于生产者和消费者的问题,首先通过缓冲区生产随机数,然后生产者put出来,接着消费者用get方法获得这个数字,同时进行判别是否为素数即可。

由分析可得代码如下:

class BufferArea{//缓冲区

      public int d;

      private boolean isEmpty=true;

      public synchronized void put(int i) {

            while(!isEmpty)

                  try {wait();}catch(InterruptedException e) {;}

            d=i;isEmpty=false;notify();

      }

      public synchronized int get() {

            while(isEmpty)try {wait();}catch(InterruptedException e) {;}

            isEmpty=true;notify();

            return d;

      }

}

class ThreadPutNumber extends Thread{

      private BufferArea ba;int z;

      public ThreadPutNumber(BufferArea b) {ba=b;}

      private int[] a=new int[100];

      public void run() {

            for(z=0;z<a.length;z++) {

                  a[z]=(int)(Math.random()*100+1);

                  ba.put(a[z]);

            }

            try {

                  sleep(1000);

            } catch (InterruptedException e) {

                  e.printStackTrace();

            }

      }

}



class ThreadGetNumber extends Thread{

      private BufferArea ba;

      ThreadPutNumber t;

      private boolean flag =true;

      public ThreadGetNumber (BufferArea b) {ba=b;}

       

      public void run() { 

            for (int j = 1; j<6; j++){

            int num=ba.get();

            System.out.print("put number is:"+num+"\t");

            for(int i=2;i<num-1;i++) {

                  if(num%2==0) {

                       flag=false;

                  }

            } 

            if(flag) {

            System.out.println(num+"is a prime!");

            }

            else {

                  System.out.println(num+"is not a prime!");

            }

            }

            try {

                  sleep(1000);

            } catch (InterruptedException e) {

                  e.printStackTrace();

            }

      }

}

       



public class App {

public static void main(String[] args) throws InterruptedException {

      BufferArea b=new BufferArea();

      ThreadGetNumber t1=new ThreadGetNumber(b); t1.start();

      (new ThreadPutNumber(b)).start();

      t1.join();

      System.out.println("Main is over!");

}

} 

四、调试过程及运行结果(详细记录在调试过程中出现的问题及解决方法。记录实验执行的结果)

小实验1:设计一个线程类,它能输出 50 以内的奇数或偶数。用书中介绍的四种构造线程方法,创建两个线程对象,分别输出奇数和偶数。

小实验2:给定容量 1000 的 int 型数组,依次存储数据 0~999。下面代码采用多线程技术计算其累加和。

 

小实验3:功能:实现多人竞争打电话,借助互斥机制,确保每个人的说话是连续 的。 class DianHuaTing{//此类对象仅提供多人打电话的共享资源 private final String dht="我是电话亭"; } class App{ public static void main (String[] args) { DianHuaTing d=new DianHuaTing(); String[] s1={"1","2","3"}; String[] s2={"A","B","C","D","E"}; String[] s3={"你好,","我也好,","大家都好!"}; Talkers t1=new Talkers(d,"张三",s1); Talkers t2=new Talkers(d,"李四",s2); Talkers t3=new Talkers(d,"王五",s3); t1.start (); t2.start (); t3.start (); } }

 

④小实验4:假设某个银行,它可以授受顾客的汇款,每做一次汇款,便可计算出汇 款的总额。现有两个顾客对同一个银行帐号操作,一个顾客分 3 次,每次 将 100 元钱存入,要求存入后将钱的总额输出。

 

小实验5:类 BufferArea 用于产生一个[1..100]的随机整数,并可取出此数。存数线 程类 ThreadPutNumber 将数存入缓冲区。读数线程类 ThreadPutNumber 从 缓冲区读取数并判断是否是素数。要求 main 线程最后结束。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值