多线程之赛跑游戏

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 booleanwin;//是否到达了终点true为到达,false为没到达

private booleanisRun;//是否继续跑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开发,赛跑游戏,游戏开发,软件编程)