多線程之賽跑遊戲

  在corejava的課程中,有一個重要的知識點,就是線程。 java

 那什麼是線程呢?線程,是「進程」中某個單一順序的控制流。而進程和流程的最大區別就在於,每一個進程都會獨享一塊存儲區域,多個線程只能共享此進程的這塊存儲區域。 dom

那線程會給咱們的java程序帶來什麼好處呢?好處一,能夠實現並行,好處二,能夠更有效的利用資源。 學習

下面咱們就編寫一個小小的賽跑遊戲來看看線程給咱們程序帶來的驚喜吧。 this

首先,我們先看看程序最後完成的效果,及操做流程: spa

遊戲一開始將直接進入主題,簡潔的界面,無需說明文檔,一眼便知如何操做。(見圖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

相關文章
相關標籤/搜索