多线程之赛跑游戏

  在corejava的课程中,有一个重要的知识点,就是线程。

 那什么是线程呢?线程,是“进程”中某个单一顺序的控制流。而进程和流程的最大区别就在于,每个进程都会独享一块存储区域,多个线程只能共享此进程的这块存储区域。

那线程会给我们的java程序带来什么好处呢?好处一,可以实现并行,好处二,可以更有效的利用资源。

下面我们就编写一个小小的赛跑游戏来看看线程给我们程序带来的惊喜吧。

首先,咱们先看看程序最后完成的效果,及操作流程:

游戏一开始将直接进入主题,简洁的界面,无需说明文档,一眼便知如何操作。(见图1 
 
多线程之赛跑游戏 
        

   1:游戏一开始的界面

    选择好我们要支持的运动员后,点击确定按钮,此时游戏还没有开始,但我们已不可再改变支持的对象了。(见图2

多线程之赛跑游戏

2:下注后的界面

好吧,既然不能更改,那么就让比赛快点开始吧!“蜗牛,加油!加油!”(见图3

多线程之赛跑游戏

 

图3:游戏开始后的界面

 哦也!蜗牛赢了!看到了吗,结果就在图4里,哈哈哈,点击确定后,400分就拿到手了!

多线程之赛跑游戏

多线程之赛跑游戏

图4 出结果后的界面

 真是一场痛快的比赛!

现在,咱们来进行一下赛后分析,上面这个小游戏究竟有多少个线程呢?我听到有人说“这个很容易就看出来了,一共就3个吗,每个参赛的跑者,都是一个线程”。真的只是表面看到的这样吗?



这个程序一共有5个线程!



   不信吗?那听我来说说:第1个线程,就是被大家忽略了,却有非常熟悉的main。这个是我们java 程序运行时,必定会运行的,也是我们学习java时最早接触的一个线程。第234 线程,就是大家说的,那三个赛跑者,每一个都是一个独立的线程。第5个线程,从图上是看不到的,却又是一个非常重要的线程,它甘居幕后,担任着发令,裁决输赢的任务,我们暂且把它叫做“裁判”吧。



  整个游戏的过程我们了解了,所包含的线程我们也都分析了,下面的时间就是着手实现的阶段了:

打着MVC的旗号,项目结构成了下面这个样子:

多线程之赛跑游戏

 


  images:中放置着,程序所需要的全部图片



vo:里放着我们的一个实体类



enter:里存放着程序的入口



view:里存放着程序的界面



control里存放着“裁判”类和监听器。



 界面部分的编写我就不细说了,就是要继承JFrame来定义我们自己的窗体。顺便说一句,那个跑道是通过画图绘制的背景。别忘了给按钮添加监听器哦!



今天的主题是线程,那么我们就要仔细看看线程的代码了:



 java中实现线程的有两种途径,一种是继承Thread类,还有一种是实现Runnable接口。下面的关于运动员裁判的实现,我都统一使用了第二种方法,就是实现Runnable接口。具体代码如下:







 

 

package saipao.vo;


 


 

import java.awt.Image;


 

import java.awt.Point;


 

import java.util.Random;


 


 

import javax.swing.ImageIcon;


 


 

public class Runners implements
  Runnable{


 

       private
  String name; //
名称


 

       private
  Point weiZhi;//
位置xy的坐标


 

       private
  ImageIcon imgBig; //
大图片


 

       private
  ImageIcon imgSmall; //
小图标


 

       private
  boolean flag; //
是否被下注,初值为false


 

       private
  boolean  win;//
是否到达了终点  
 
true
为到达,false为没到达


 

       private
  boolean   isRun;//
是否继续跑 true为继续,false为停止


 

       /*


 

        * 名称、坐标、图片,小图标是只读的,只有get方法


 

        * */


 

      


 

       public
  boolean isFlag() {


 

              return
  flag;


 

       }


 

       public
  void setFlag(boolean flag) {


 

              this.flag
  = flag;


 

       }


 

       public
  String getName() {


 

              return
  name;


 

       }


 

       public
  Point getWeiZhi() {


 

              return
  weiZhi;


 

       }


 

       public
  ImageIcon getImgBig() {


 

              return
  imgBig;


 

       }


 

       public
  ImageIcon getImgSmall() {


 

              return
  imgSmall;


 

       }


 

      


 

       public
  void setWin(boolean win) {


 

              this.win
  = win;


 

       }


 

      


 

       public
  boolean isRun() {


 

              return
  isRun;


 

       }


 

       public
  void setRun(boolean isRun) {


 

              this.isRun
  = isRun;


 

       }


 

       public
  Runners(String name,int x,int y,String imageName) {


 

              super();


 

              this.name
  = name;


 

              this.weiZhi=new
  Point(x, y);


 

              this.imgBig=new
  ImageIcon(this.getClass().getResource("/images/"+imageName+".gif"));


 

              this.imgSmall=new
  ImageIcon(this.getClass().getResource("/images/"+imageName+"1.GIF"));


 

              this.isRun=true;
  //
默认为继续跑


 

             


 

       }


 

      


 

       //退到起点


 

       public
  void fuWei(){


 

              this.weiZhi.move(0,
  (int)this.weiZhi.getY());


 

              this.flag=this.win=false;


 

              this.isRun=true;


 

       }


 

       //是否押对了


 

       public
  boolean isWiner(){


 

              return
  this.flag&this.win;


 

       }


 

   
 
//
重写Runnable接口中的Run方法,实现 x y坐标的改变


 

      


 

       public
  void run() {


 

              Random
  rd=new Random(); //
用于控制速度的随机数


 

              while(this.isRun){


 

                     int
  x=(int)this.weiZhi.getX();


 

                     x+=rd.nextInt(10)+1;


 

                     this.weiZhi.move(x,(int)this.weiZhi.getY());               


 

                     try
  {


 

                            Thread.sleep(100);


 

                     }
  catch (InterruptedException e) {


 

                            //
  TODO Auto-generated catch block


 

                            e.printStackTrace();


 

                     }


 

              }


 

             


 

       }


 

      


 


 

}


 




好了,运动员的代码我们看到了,你发现了Runnable接口中声明了几个方法了吗? 答对了,就一个叫做Run的方法。当线程启动后,就将会执行Run方法中的代码。知道执行完毕退出run方法,此线程就死亡了。



光有运动员,没有裁判怎么行!







 

 

package saipao.control;


 


 

import java.util.Vector;


 


 

import javax.swing.JOptionPane;


 


 

import saipao.view.MainFrame;


 

import saipao.vo.Runners;


 


 

/*


 

 * 裁判类,用来确定是否有到达终点的赛跑者


 

 * */


 

public class CaiPan implements
  Runnable{


 

    
 
Vector<Runners> vt;//
运动员集合


 

    
 
int width;//
终点线的位置


 

        Thread [] thread;


 

        MainFrame mf;


 

       public
  CaiPan(MainFrame mf) {


 

              super();


 

              this.vt
  = mf.getRnList();


 

              this.width
  =mf.getZhongDianXian();


 

              this.mf=mf;


 

       }


 


 

       //运动员开始跑


 

   
 
private void startRun(){


 

   
 
      thread=new
  Thread[vt.size()];


 

   
 
      //
给三个线程赋值并启动


 

   
 
      for(int
  i=0;i<thread.length;i++){


 

   
 
             thread[i]=new
  Thread(vt.get(i));


 

   
 
             thread[i].start();


 

   
 
      }


 

   
 
}


 

      


 

       //判断是否有人到达重点


 

       public
  void run() {


 

              //调用开跑方法


 

              this.startRun();


 

              //判断是否有运动员到达终点


 

              while(vt.get(0).isRun()){


 

                     mf.lblWeiZhi();


 

                     for(int
  i=0;i<vt.size();i++){


 

                            int
  x=(int)vt.get(i).getWeiZhi().getX();//
得到运动员的x坐标


 

                            if(x>=this.width){


 

                                   vt.get(i).setWin(true);//设置当前运动员赢了


 

                                   //并通知所有运动员都不用再跑了


 

                                   for(int
  j=0;j<vt.size();j++){


 

                                          vt.get(j).setRun(false);


 

                                   }


 

                                   //退出判断是否到达终点的循环


 

                                   break;


 

                            }


 

                     }            


 

              }


 

              //赛跑结束,判断是输还是赢,并计算金额


 

              boolean
  flag=false;


 

              for(int
  i=0;i<vt.size();i++){


 

                     if(vt.get(i).isWiner()){


 

                            flag=vt.get(i).isWiner();


 

                            break;


 

                     }


 

              }


 

              if(flag){


 

                     JOptionPane.showMessageDialog(mf,
  "you win!");


 

                    


 

              }else{


 

                     JOptionPane.showMessageDialog(mf,
  "you lost!");


 

              }


 

              mf.changeMoney(flag);


 

              mf.btnKongZhi(2,
  true);


 

       }



 


 

}


 


有没有注意到,Runnable接口仅仅是提供了线程启动后要调用的功能(run),并没有提供启动线程的功能。要想真正的使线程运行起来,还是要通过Thread的帮助,因为Thread类中提供了启动线程的start()功能。



剩下的就是在对应的监听事件中,命令我们的裁判发号施令,开始我们的比赛了。



在和大家说byebye之前,还想请大家思考一下,运动员(Runners)那个类除了通过实现Runnable接口来编写线程程序,还有没有别的方式,使其成为线程?如果有,那么会不会影响我们其他类的代码呢?



立即动手吧!我会一直期待着你的答案哦!



作者:中软卓越天津ETC



你可能感兴趣的:(多线程,java开发,软件开发,赛跑游戏)