在JavaSE中,多线程是一个重要的内容。

我们要了解多线程的概念,就要先了解进程的概念;要了解进程的概念,就离不开操作系统的概念。

在一台正常运行的电脑中,计算机硬件(如CPU、内存、硬盘、网卡、显示器、键盘、鼠标等)提供了基础的硬件环境;在硬件之上,是操作系统,这是系统级的软件程序,用来管理计算机的各项软件资源,是人机交互中的关键环节;在操作系统之上,则是各类应用软件程序,比如QQ、微信、浏览器等。

进程是一个动态的概念,程序则是一个静态的概念。程序在操作系统中运行起来时,需要操作系统为其分配相应的内存、CPU等资源,成为进程。不同的进程,独享各自的内存、CPU等资源。这也是进程安全性所不可缺少的。所以,进程是操作系统分配CPU及各类系统资源的基本单位。

当进程运行起来时,通常会有多个子任务,以游戏为例,里面需要绘制游戏面板,如果游戏里有多个角色的人物进行并发活动,还需要能够获得相应的CPU资源,从而取得CPU的执行权,以进入运行状态。同时,在同一个游戏中,每个角色的有关状态数据,可以为该游戏中的其他角色所获取。由此可见,一个进程中可以有多个子任务,这些子任务需要并发轮流获取CPU的执行权,同时可以共享进程的内存资源。进程中的这些子任务就被称为线程,多个子任务就是多个线程。线程是进程中分配CPU资源的基本单位,线程不可以脱离进程而存在。

Java语言本身就是一种多线程语言。比如,在JavaSE的一个Java工程中,JVM通过main入口函数运行起来时,同时还会有GC(垃圾回收器)运行起来,以等待回收Java堆内存中变为垃圾的对象,以节省堆内存空间。

在做完上述知识铺垫和准备后,我接下来通过一个赛跑游戏,来为大家演示Java多线程的运用。

在这里,我先将该赛跑游戏的运行效果予以演示:

每次登录该游戏,会弹出一个提示框,告知用户是第几次登录,并有温馨提示。

点击“确定”或关闭该提示框,则进入游戏界面。该界面分为上下两部分,上半部分为游戏跑道,4个赛手,共4个跑道;下半部分为游戏控制面板,提示用户选择赛手,输入押注金额,以及点击“开始”按钮开始赛跑,还有“重新开始”按钮以回到比赛准备的状态等。

点击“开始”按钮后,进入赛跑游戏,游戏面板中的4个赛手开始奔跑,对于先跑到终点的赛手,会弹出提示框予以庆祝;如果用户押注失败,则用户本金会予以相应减少;如果用户押注成功,则用户本金会予以相应增加。

好了,演示完上述游戏后,接下来谈下开发思路。

首先,完成游戏前端部分。先绘制一个游戏窗体,窗体上添加面板,面板上添加各类所需的组件。

其次,游戏前端部分完成后,根据面向对象的思想,将赛手抽象为一个类,将与赛手有关的各种属性与功能均由该类实现;同时,主线程负责绘制游戏前端,各个赛手要运行时,则通过开辟子线程来实现。

再次,当赛跑游戏结束时,根据产生的第一名,刷新本金,弹出庆祝框,同时提示用户是成功或者失败;此外,将用户的本金与登录次数存入一个属性文件,用户本金与登录次数的变化会实时更新到属性文件中。

Step 1

请看游戏前端代码:

  1. package runningGame;
  2.  
  3. import java.awt.BorderLayout;
  4. import java.awt.Color;
  5. import java.awt.Graphics;
  6. import java.awt.Image;
  7. import java.awt.Toolkit;
  8. import java.awt.event.ActionEvent;
  9. import java.awt.event.ActionListener;
  10. import java.io.BufferedInputStream;
  11. import java.io.BufferedOutputStream;
  12. import java.io.FileInputStream;
  13. import java.io.FileNotFoundException;
  14. import java.io.FileOutputStream;
  15. import java.io.IOException;
  16. import java.io.InputStream;
  17. import java.io.OutputStream;
  18. import java.math.BigInteger;
  19. import java.util.Properties;
  20. import java.util.ResourceBundle;
  21.  
  22. import javax.swing.BorderFactory;
  23. import javax.swing.ButtonGroup;
  24. import javax.swing.JButton;
  25. import javax.swing.JFrame;
  26. import javax.swing.JLabel;
  27. import javax.swing.JOptionPane;
  28. import javax.swing.JPanel;
  29. import javax.swing.JRadioButton;
  30. import javax.swing.JTextField;
  31.  
  32. /**
  33. * 游戏 面板设计
  34. * @author 李章勇
  35. * 常量分析:
  36. * 4个赛手
  37. * 赛手编号
  38. * 胜利感言
  39. * 跑道面板
  40. * 4个跑道,每个跑道一张背景图
  41. * 每个跑道上各有一个准备状态的赛手
  42. * 终点线
  43. * 控制面板
  44. * 4个单选按钮[表示赛手】
  45. * 提示选择赛手、输入押注,押注输入框
  46. * 我的本金提示
  47. * 开始按钮,重新开始按钮
  48. * 多个子线程共用同一段代码,赛手类
  49. */
  50. public class GameJFrame extends JFrame{
  51. //赛道背景面板
  52. GamePanel jp_game=new GamePanel();
  53. //4张跑道背景图
  54. Image[] img_back=new Image[StaticIntString.NUM];
  55. //每个跑道上处于准备状态的小人
  56. Image[] img_ready=new Image[StaticIntString.NUM];
  57. //每个跑道上奔跑中的小人
  58. Image[] img_run=new Image[StaticIntString.NUM];
  59.  
  60. //游戏控制面板
  61. JPanel jp_control=new JPanel();
  62. //4个单选按钮
  63. static JRadioButton[] jrb_mans=new JRadioButton[StaticIntString.NUM];
  64. //按钮组
  65. ButtonGroup bg=new ButtonGroup();
  66. //提示选择姓名并输入金额
  67. JLabel jl_inputTips=new JLabel(StaticIntString.INPUT_TIPS1);
  68. //输入押注金额
  69. JTextField jtf_cost=new JTextField(10);
  70. JLabel jl_winFailTips=new JLabel("本次输赢:");
  71. JLabel jl_winFail=new JLabel(StaticIntString.WIN_FAIL);
  72. //本金提示
  73. JLabel jl_ownMoneyTips=new JLabel("我的本金:");
  74. static Properties pro=new Properties();
  75. //从属性文件里读取本金
  76. static ResourceBundle resource=ResourceBundle.getBundle("runningGame.infos");
  77. String ownMoney=resource.getString("ownMoney");
  78. BigInteger bi_times=new BigInteger(resource.getString("times"));
  79. static BigInteger bi_bankruptcy=new BigInteger(resource.getString("bankruptcy"));
  80. String ownMoney_System=resource.getString("ownMoney_System");
  81. //本金
  82. JLabel jl_ownMoney=new JLabel(ownMoney);
  83. //开始按钮
  84. JButton jbt_start=new JButton("开始");
  85. //重新开始按钮
  86. JButton jbt_restart=new JButton("重新开始");
  87. static String selectedName;
  88. RunningMan[] mans=new RunningMan[StaticIntString.NUM];
  89.  
  90. public GameJFrame() {
  91. if(bi_times.toString().equals("1")){
  92. JOptionPane.showMessageDialog(this, "首次登陆,欢迎光临!\n系统赠予您10000元,\n祝您玩得开心愉快!\n只是玩玩,不要沉溺赌博哦");
  93. }else{
  94. JOptionPane.showMessageDialog(this, "您这是第 "+bi_times.toString()+" 次登陆,欢迎光临!\n祝您玩得开心愉快!\n只是玩玩,不要沉溺赌博哦");
  95. }
  96. bi_times=bi_times.add(new BigInteger("1"));
  97. try {
  98. BufferedInputStream fis=new BufferedInputStream(new FileInputStream("src//runningGame//infos.properties"));
  99. BufferedOutputStream fos=new BufferedOutputStream(new FileOutputStream("src//runningGame//infos.properties"));
  100. String ownMoney_System=resource.getString("ownMoney_System");;
  101. try {
  102. pro.load(fis);
  103. } catch (IOException e1) {
  104. e1.printStackTrace();
  105. }
  106. pro.setProperty("times", bi_times.toString());
  107. pro.setProperty("ownMoney", ownMoney);
  108. pro.setProperty("bankruptcy", bi_bankruptcy.toString());
  109. pro.setProperty("ownMoney_System", ownMoney_System);
  110. try {
  111. pro.store(fos, "");
  112. fis.close();
  113. fos.close();
  114. } catch (IOException e) {
  115. e.printStackTrace();
  116. }
  117. } catch (FileNotFoundException e) {
  118. e.printStackTrace();
  119. }
  120.  
  121. for(int i=0;i<StaticIntString.NUM;i++){
  122. img_back[i]=Toolkit.getDefaultToolkit().createImage("imgBack//"+(i+1)+".jpg");
  123. img_ready[i]=Toolkit.getDefaultToolkit().createImage("imgReady//"+(i+1)+"2.gif");
  124. img_run[i]=Toolkit.getDefaultToolkit().createImage("imgRun//"+(i+1)+"1.gif");
  125. jrb_mans[i]=new JRadioButton(StaticIntString.NAMES[i]);
  126. bg.add(jrb_mans[i]);
  127. jp_control.add(jrb_mans[i]);
  128. }
  129. jbt_start.addActionListener(new ActionListener(){
  130. boolean isSelected=false;
  131. public boolean judgeSelected(){
  132. for(JRadioButton j:jrb_mans){
  133. if(j.isSelected()){
  134. isSelected=true;
  135. }
  136. }
  137. return isSelected;
  138. }
  139.  
  140. @Override
  141. public void actionPerformed(ActionEvent arg0) {
  142. if(!judgeSelected()){
  143. JOptionPane.showMessageDialog(GameJFrame.this, "您还没选人呢",
  144. "看着点", JOptionPane.WARNING_MESSAGE);
  145. return;
  146. }
  147. if(jtf_cost.getText().trim().length()==0){
  148. JOptionPane.showMessageDialog(GameJFrame.this, "您还没下注呢",
  149. "看着点", JOptionPane.WARNING_MESSAGE);
  150. return;
  151. }
  152. char[] cs=jtf_cost.getText().toCharArray();
  153. for(int i=0;i<cs.length;i++){
  154. if(cs[i]<'0' || cs[i]>'9'){
  155. JOptionPane.showMessageDialog(GameJFrame.this, "您输入的不是数字",
  156. "看着点", JOptionPane.WARNING_MESSAGE);
  157. jtf_cost.setText("");
  158. return;
  159. }
  160. if(cs[0]=='0'){
  161. JOptionPane.showMessageDialog(GameJFrame.this, "数字首位不能是0",
  162. "看着点", JOptionPane.WARNING_MESSAGE);
  163. jtf_cost.setText("");
  164. return;
  165. }
  166. }
  167. BigInteger bi_jtf_cost=new BigInteger(jtf_cost.getText());
  168. BigInteger bi_jl_ownMoney=new BigInteger(jl_ownMoney.getText());
  169.  
  170. if((bi_jtf_cost.compareTo(bi_jl_ownMoney))>0){
  171. JOptionPane.showMessageDialog(GameJFrame.this, "您的下注金额不能超过本金哦",
  172. "看着点", JOptionPane.WARNING_MESSAGE);
  173. jtf_cost.setText("");
  174. return;
  175. }
  176.  
  177. for(JRadioButton j:jrb_mans){
  178. if(j.isSelected()){
  179. selectedName=j.getText();
  180. break;
  181. }
  182. }
  183. for(JRadioButton j:jrb_mans){
  184. j.setEnabled(false);
  185. }
  186.  
  187. jtf_cost.setEditable(false);
  188. jl_inputTips.setText(StaticIntString.INPUT_TIPS2);
  189. jbt_restart.setEnabled(true);
  190. jbt_start.setEnabled(false);
  191. RunningMan.isEnd=false;
  192. RunningMan.canRun=true;
  193. RunningMan.num=0;
  194. for(int i=0;i<StaticIntString.NUM;i++){
  195. mans[i].img=img_run[i];
  196. mans[i].start();
  197. }
  198. }
  199. });
  200. jbt_restart.addActionListener(new ActionListener(){
  201.  
  202. @Override
  203. public void actionPerformed(ActionEvent arg0) {
  204.  
  205. for(int i=0;i<StaticIntString.NUM;i++){
  206. jrb_mans[i].setText(StaticIntString.NAMES[i]);
  207. jrb_mans[i].setEnabled(true);
  208. }
  209. jl_inputTips.setText(StaticIntString.INPUT_TIPS1);
  210. jtf_cost.setText("");
  211. jtf_cost.setEditable(true);
  212. jl_winFail.setForeground(Color.BLACK);
  213. jl_winFail.setText(StaticIntString.WIN_FAIL);
  214. jbt_start.setEnabled(true);
  215. jbt_restart.setEnabled(false);
  216. RunningMan.isEnd=true;
  217. RunningMan.canRun=false;
  218. bg.clearSelection();
  219. for(int i=0;i<StaticIntString.NUM;i++){
  220. mans[i]=new RunningMan(StaticIntString.NAMES[i], 0, (jp_game.getHeight()*i)/4+30, img_ready[i], GameJFrame.this);
  221. }
  222. }
  223. });
  224.  
  225. jp_control.setBorder(BorderFactory.createTitledBorder("游戏控制系统"));
  226. jp_control.add(jl_inputTips);
  227. jp_control.add(jtf_cost);
  228. jp_control.add(jl_winFailTips);
  229. jp_control.add(jl_winFail);
  230. jp_control.add(jl_ownMoneyTips);
  231. jp_control.add(jl_ownMoney);
  232. jp_control.add(jbt_start);
  233. jp_control.add(jbt_restart);
  234. this.add(jp_game,BorderLayout.CENTER);
  235. this.add(jp_control, BorderLayout.SOUTH);
  236. setResizable(false);
  237. setTitle("赛跑游戏 ---作者:李章勇");
  238. setBounds(200, 100, 1000, 600);
  239. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  240. setVisible(true);
  241. for(int i=0;i<StaticIntString.NUM;i++){
  242. mans[i]=new RunningMan(StaticIntString.NAMES[i], 0, (jp_game.getHeight()*i)/4+30, img_ready[i], this);
  243. }
  244. }
  245.  
  246. class GamePanel extends JPanel{
  247. @Override
  248. public void paint(Graphics g) {
  249. super.paint(g);
  250. for(int i=0;i<StaticIntString.NUM;i++){
  251. g.drawImage(img_back[i], 0, (this.getHeight()*i)/4,this.getWidth(),this.getHeight()/4+30,this);
  252. mans[i].drawSelf(g, this);
  253.  
  254. }
  255. g.setColor(Color.RED);
  256. g.fillRect(850, 0, 5, this.getHeight());
  257. }
  258. }
  259.  
  260. public static void main(String[] args) {
  261. new GameJFrame();
  262. }
  263. }

Step 2

将赛手抽象为一个类,同时创建一个接口工具,存储常数,便于对数据的统一管理;再创建一个名为“infos.properties”的属性文件,将用户本金、登录次数等信息存储到属性文件里,以备更新。

  1. package runningGame;
  2.  
  3. public interface StaticIntString {
  4. public static final int NUM=4;
  5. public static final String[] NAMES={ "1号选手", "2号选手", "3号选手", "4号选手" };
  6. public static final String[] WINS={ "预测未来的最好方法,就是创造未来.", "人生重要的不是所站的位置,而是所朝的方向.",
  7. "如你想要拥有完美无暇的友谊,可能一辈子找不到兄弟姐妹","正因年轻咱们一无所有,也正正因年轻咱们将拥有一切." };
  8. public static final String INPUT_TIPS1="请选择赛手并输入金额:";
  9. public static final String INPUT_TIPS2="本次下注金额:";
  10. public static final String GET_WIN="[获胜]";
  11. public static final String WIN_FAIL="[Win/Fail]";
  12. public static final String WIN_STATE="[Win]";
  13. public static final String FAIL_STATE="[Fail]";
  14. } 
  1. 属性文件infos.properties: 
  1. #破产次数,登录次数,系统默认赠予的本金,用户的实际本金;只要用户本金小于等于0,系统会自动为用户赠予初始本金。
  2. #Fri Dec 01 09:34:34 CST 2017
  3. bankruptcy=0
  4. times=1
  5. ownMoney_System=10000
  6. ownMoney=10000  
  1. 赛手类RunningMan: 
  1. package runningGame;
  2.  
  3. import java.awt.Graphics;
  4. import java.awt.Image;
  5. import java.io.BufferedInputStream;
  6. import java.io.BufferedOutputStream;
  7. import java.io.FileInputStream;
  8. import java.io.FileNotFoundException;
  9. import java.io.FileOutputStream;
  10. import java.io.IOException;
  11. import java.math.BigInteger;
  12. import java.util.Random;
  13.  
  14. import javax.swing.JOptionPane;
  15. import javax.swing.JPanel;
  16. import javax.swing.JRadioButton;
  17.  
  18. /**
  19. * 赛手的属性:姓名,坐标(x/y),自身图像,准备状态的图像,关联的窗体
  20. * 位移所需的随机数Random,
  21. * 第一名NO1
  22. * 是否能跑的状态canRun
  23. * 比赛是否结束isEnd
  24. * 每个赛手跑完时计数num
  25. *
  26. * 赛手画自己的方法drawSelf
  27. * 赛手跑步位移的方法move
  28. * 子线程运行的run方法
  29. *
  30. * @author 李章勇
  31. *
  32. */
  33. public class RunningMan extends Thread {
  34. public String name;
  35. private int x_point,y_poinit;
  36. public Image img;
  37. private Image imgReady;
  38. private GameJFrame jf_game;
  39. static Random rand=new Random();
  40. static RunningMan NO1;
  41. static boolean canRun=true;
  42. static boolean isEnd=false;
  43. static int num=0;
  44. static BigInteger bi_ownMoney;
  45.  
  46. public RunningMan(String name,int x_point,int y_point,Image img,GameJFrame jf_game) {
  47. this.name=name;
  48. this.x_point=x_point;
  49. this.y_poinit=y_point;
  50. this.img=img;
  51. this.imgReady=img;
  52. this.jf_game=jf_game;
  53. }
  54.  
  55. public void setName2(String name){
  56. this.name=name;
  57. }
  58. public String getName2(){
  59. return name;
  60. }
  61.  
  62. public void drawSelf(Graphics g,JPanel jp){
  63. g.drawImage(img, x_point, y_poinit, jp);
  64. }
  65.  
  66. public void move(){
  67. x_point+=10+rand.nextInt(30);
  68. }
  69.  
  70. @Override
  71. public void run() {
  72. while(x_point<=850 && canRun){
  73. try {
  74. Thread.sleep(100);
  75. } catch (InterruptedException e) {
  76. e.printStackTrace();
  77. }
  78. move();
  79. }
  80. synchronized(String.class){
  81. if(canRun){
  82. x_point=850;
  83. img=imgReady;
  84. num++;
  85. }
  86. if(!isEnd){
  87. NO1=this;
  88. isEnd=true;
  89. }
  90. if(num==4){
  91. System.out.println("本次比赛第一名:"+NO1.name);
  92. //根据比赛结果,修改金额 类
  93. bi_ownMoney=new GetResult(jf_game).getRightMoney();
  94. new WinDialog();
  95. try {
  96. BufferedInputStream fis = new BufferedInputStream(new FileInputStream("src//runningGame//infos.properties"));
  97. BufferedOutputStream fos=new BufferedOutputStream(new FileOutputStream("src//runningGame//infos.properties"));
  98. try {
  99. GameJFrame.pro.load(fis);
  100. if((bi_ownMoney.compareTo(new BigInteger("0"))<=0)){
  101. JOptionPane.showMessageDialog(jf_game, "您已没有本金,\n系统不差钱儿,再次赠予您 10000 元!\n祝您玩得开心哦!",
  102. "看着点", JOptionPane.WARNING_MESSAGE);
  103. jf_game.jl_ownMoney.setText(GameJFrame.resource.getString("ownMoney_System"));
  104. GameJFrame.pro.setProperty("ownMoney", GameJFrame.resource.getString("ownMoney_System"));
  105. BigInteger bi_bankruptcy=new BigInteger(GameJFrame.resource.getString("bankruptcy")).add(new BigInteger("1"));
  106. GameJFrame.pro.setProperty("bankruptcy", bi_bankruptcy.toString());
  107.  
  108. }else{
  109. jf_game.jl_ownMoney.setText(bi_ownMoney.toString());
  110. GameJFrame.pro.setProperty("ownMoney", bi_ownMoney.toString());
  111. }
  112. GameJFrame.pro.store(fos, "");
  113. fis.close();
  114. fos.close();
  115. } catch (IOException e1) {
  116. e1.printStackTrace();
  117. }
  118. } catch (FileNotFoundException e1) {
  119. e1.printStackTrace();
  120. }
  121. for(JRadioButton j:GameJFrame.jrb_mans){
  122. if(NO1.name.equals(j.getText())){
  123. j.setText(j.getText()+StaticIntString.GET_WIN);
  124. }
  125. }
  126. }
  127. }
  128. }
  129. }

 刷新用户本金的类: 

  1. package runningGame;
  2.  
  3. import java.awt.Color;
  4. import java.io.BufferedOutputStream;
  5. import java.io.FileNotFoundException;
  6. import java.io.FileOutputStream;
  7. import java.io.IOException;
  8. import java.math.BigInteger;
  9.  
  10. import javax.swing.JButton;
  11. import javax.swing.JLabel;
  12. import javax.swing.JOptionPane;
  13. import javax.swing.JRadioButton;
  14. import javax.swing.JTextField;
  15.  
  16. /**
  17. * 需要的属性
  18. * 代表四个赛手的按钮
  19. * 输入的金额
  20. * 输赢状态
  21. * 本金
  22. * 关联的窗体
  23. * 获得比赛后、发生变化的钱数getRightMoney
  24. * 设置本金新的数值setNewMoney
  25. * @author 李章勇
  26. *
  27. */
  28. public class GetResult {
  29. private JRadioButton[] jrb_mans;
  30. private JTextField jtf_cost;
  31. private JLabel jl_winFail;
  32. private JLabel jl_ownMoney;
  33.  
  34. public GetResult(GameJFrame jf_game) {
  35. this.jrb_mans=jf_game.jrb_mans;
  36. this.jtf_cost=jf_game.jtf_cost;
  37. this.jl_winFail=jf_game.jl_winFail;
  38. this.jl_ownMoney=jf_game.jl_ownMoney;
  39. }
  40.  
  41. public BigInteger getRightMoney(){
  42. BigInteger bi_ownMoney=new BigInteger(jl_ownMoney.getText());
  43. BigInteger bi_cost=new BigInteger(jtf_cost.getText());
  44. if(GameJFrame.selectedName!=null && GameJFrame.selectedName.equals(RunningMan.NO1.name)){
  45. jl_winFail.setForeground(Color.GREEN);
  46. jl_winFail.setText(StaticIntString.WIN_STATE);
  47. bi_ownMoney=bi_ownMoney.add(bi_cost);
  48. jl_ownMoney.setText(bi_ownMoney.toString());
  49. }else{
  50. jl_winFail.setForeground(Color.RED);
  51. jl_winFail.setText(StaticIntString.FAIL_STATE);
  52. bi_ownMoney=bi_ownMoney.subtract(bi_cost);
  53. jl_ownMoney.setText(bi_ownMoney.toString());
  54. }
  55. return bi_ownMoney;
  56. }
  57. }

  弹出庆祝框的类WinDialog:

  1. package runningGame;
  2.  
  3. import java.awt.Color;
  4. import java.awt.Graphics;
  5. import java.awt.Image;
  6. import java.awt.Toolkit;
  7. import java.util.Random;
  8.  
  9. import javax.swing.JDialog;
  10. import javax.swing.JFrame;
  11. import javax.swing.JPanel;
  12. /**
  13. * 对话框背景图
  14. * 4个赛手获胜时的图片
  15. * 自定义面板
  16. * 随机数,随机获取胜利宣言
  17. * @author 李章勇
  18. *
  19. */
  20. public class WinDialog extends JDialog{
  21. Image img_back=Toolkit.getDefaultToolkit().createImage("imgWin//winbg.jpg");
  22. Image[] img_wins=new Image[StaticIntString.NUM];
  23. WinJPanel wp=new WinJPanel();
  24. Random rand=new Random();
  25. int num=0;
  26.  
  27. public WinDialog() {
  28. for(int i=0;i<img_wins.length;i++){
  29. img_wins[i]=Toolkit.getDefaultToolkit().createImage("imgWin//"+(i+1)+"3.gif");
  30. }
  31. wp.setBounds(100, 100, 400, 300);
  32. add(wp);
  33. setTitle("胜利墙");
  34. setBounds(300, 300, 400, 300);
  35. setResizable(false);
  36. setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
  37. setVisible(true);
  38. num=rand.nextInt(4);
  39. }
  40.  
  41. class WinJPanel extends JPanel{
  42.  
  43. @Override
  44. public void paint(Graphics g) {
  45. super.paint(g);
  46. g.drawImage(img_back, 0, 0, this.getWidth(), this.getHeight(), this);
  47.  
  48. switch(RunningMan.NO1.name){
  49. case "1号选手":
  50. g.drawImage(img_wins[0], 50, 100, this);
  51. break;
  52. case "2号选手":
  53. g.drawImage(img_wins[1], 50, 100, this);
  54. break;
  55. case "3号选手":
  56. g.drawImage(img_wins[2], 50, 100, this);
  57. break;
  58. case "4号选手":
  59. g.drawImage(img_wins[3], 50, 100, this);
  60. break;
  61. default:
  62. break;
  63. }
  64. g.setColor(Color.RED);
  65. g.drawString("本次获胜选手:"+RunningMan.NO1.name, 20, 30);
  66. g.drawString(StaticIntString.WINS[num], 20, 50);
  67. }
  68. }
  69. }

  到此,代码部分就结束了。至于代码中用到的图片,读者参考下述对图片的命名规则,收集相应的图片即可。

  到此,整个单机赛跑游戏是完成了。然而,目前在运行时,我们需要在Eclipse里运行项目才可以打开游戏,显然这种方式并不符合普通用户。为此,我们来看如何把项目打包成jar包后,再生成exe可执行文件,这样的话,用户只要双击运行该exe可执行文件,就可以打开游戏。

  在此,介绍一款将jar文件生成exe文件时用到的第三方软件:exe4j(下载地址:http://www.ej-technologies.com/download/exe4j/files):

  至于接下来应该怎样把jar包生成exe文件,有一篇博客《将java项目打包成jar包并生成可独立执行的exe文件》中已经介绍得很详细,建议读者参考。

  现在,一个完整的exe版单机赛跑游戏就制作好了。

Java多线程之赛跑游戏(含生成exe文件)的更多相关文章

  1. Java多线程之赛跑游戏

    在JavaSE中,多线程是一个重要的内容. 我们要了解多线程的概念,就要先了解进程的概念:要了解进程的概念,就离不开操作系统的概念. 在一台正常运行的电脑中,计算机硬件(如CPU.内存.硬盘.网卡.显 ...

  2. 如何打包/运行jar包,及生成exe文件

    关于如何打包/运行jar包,以及生成exe文件.之前各种查询.博客,终于搞明白究竟是咋回事.记得还做过笔记的.今天要打包生成exe用的时候,居然忘了咋怎来着.去查看之前的笔记,死活没找到(好像被删掉了 ...

  3. GUI生成exe文件

    gui如何生成exe文件: 已经有gui.m和gui.fig文件 1 安装编译器.已经安装好了vs10的. 2 设置编译器.在matlab命令行输入mex -setup,选择安装的c编译器 3 调用编 ...

  4. 如何解决exe4j生成exe文件后弹出提示信息

    使用exe4j生成exe文件时会提示以上一段信息,这个主要是没有注册导致的,在welcome to exe4j的右下角有一个注册信息的地方,去找个注册码,就OK了. 通用注册码:L-g782dn2d- ...

  5. [原创]Matlab之GUI生成EXE文件

    近期因为项目需要,简化流程,写了一些Matlab程序,并配备上了GUI界面使其简单易用.然后问题来了,可移植性.使用Matlab生成EXE文件(可以封装很多的function),然后在一台安装有Mat ...

  6. vs2010如何生成EXE文件如何更改EXE程序图标

    vs2010如何生成EXE文件 F5启动调试后,进入下面路径查找: 我的文档\Visual Studio 2010\Projects\项目名称\项目名称\bin\Debug 如何更改EXE程序图标 其 ...

  7. matlab改变GUI和figure左上角图标的方法,并生成exe文件

    1. GUI左上角图标的更改,假设GUI的Tag为figure1,在其OpeningFcn里添加h = handles.figure1; %返回其句柄newIcon = javax.swing.Ima ...

  8. pyinstaller生成exe文件失败

    我的python是3.6,目前pyinstaller并不支持,有网友建议在Github上下载源码,用pyinstaller_develop文件夹替换pyinstaller安装位置下同名文件夹.这样做之 ...

  9. c++与matlab联合编程,调用Deploytool 生成exe文件和dll文件(转)

    转自:http://www.cnblogs.com/xlw1219/archive/2012/12/25/2832222.html 首先必须知道联合编程需要知道的一些命令解释: mcc 的作用是将 . ...

随机推荐

  1. 【JavaScript】Json

    一.前言        接着上一章的内容,继续js的学习. 二.内容        解析与序列化 JSON.stringify() —— 将js对象序列化为JSON字符串,接收三个参数:1.js对象2 ...

  2. 洛谷 P1171 售货员的难题 【状压dp】

    题目描述 某乡有n个村庄(1<n<20),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0<s<1000)是已知的,且A村到B村与B村到A村的路大多不同.为了提高效率 ...

  3. 洛谷 P1715 [USACO16DEC]Lots of Triangles好多三角形 解题报告

    P1715 [USACO16DEC]Lots of Triangles好多三角形 题目描述 农民约翰希望通过卖出他拥有的一部分土地来增加收入.他在这片土地上种了\(N\)棵树(\(3\le N\le ...

  4. HDU.1394 Minimum Inversion Number (线段树 单点更新 区间求和 逆序对)

    HDU.1394 Minimum Inversion Number (线段树 单点更新 区间求和 逆序对) 题意分析 给出n个数的序列,a1,a2,a3--an,ai∈[0,n-1],求环序列中逆序对 ...

  5. python中如何优雅使用import

    http://note.youdao.com/noteshare?id=c55be6a8565f5eb586aa52244b3af010

  6. LeetCode-Evaluate Reverse Polish Notation[AC源码]

    package com.lw.leet2; /** * @ClassName:Solution * @Description: * Evaluate the value of an arithmeti ...

  7. Oracle恢复误删除表操作语句

    一.表和数据恢复 1.从回收站里查询被删除的表 select object_name,original_name,partition_name,type,ts_name,createtime,drop ...

  8. UVA 11982 Fantasy Cricket

    https://vjudge.net/problem/UVA-11982 题意: 给出一个包含’U’, ‘D’, ‘E’的字符串, ’U’ 表示需要把这个字符向后移动, ’D’表示需要把这个字符向前移 ...

  9. 分治法:三维偏序问题之CDQ分治

    我怀疑那个k是用来定界限用的 #include <cstdio> #include <cstring> #include <algorithm> using nam ...

  10. LintCode 395: First Will Win 2

    LintCode 395: First Will Win 2 题目描述 有 n 个不同价值的硬币排成一条线.两个参赛者轮流从左边依次拿走 1 或 2 个硬币,直到没有硬币为止.计算两个人分别拿到的硬币 ...