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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Step 1

请看游戏前端代码:

package runningGame;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.Properties;
import java.util.ResourceBundle; import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField; /**
* 游戏 面板设计
* @author 李章勇
* 常量分析:
* 4个赛手
* 赛手编号
* 胜利感言
* 跑道面板
* 4个跑道,每个跑道一张背景图
* 每个跑道上各有一个准备状态的赛手
* 终点线
* 控制面板
* 4个单选按钮[表示赛手】
* 提示选择赛手、输入押注,押注输入框
* 我的本金提示
* 开始按钮,重新开始按钮
* 多个子线程共用同一段代码,赛手类
*/
public class GameJFrame extends JFrame{
//赛道背景面板
GamePanel jp_game=new GamePanel();
//4张跑道背景图
Image[] img_back=new Image[StaticIntString.NUM];
//每个跑道上处于准备状态的小人
Image[] img_ready=new Image[StaticIntString.NUM];
//每个跑道上奔跑中的小人
Image[] img_run=new Image[StaticIntString.NUM]; //游戏控制面板
JPanel jp_control=new JPanel();
//4个单选按钮
static JRadioButton[] jrb_mans=new JRadioButton[StaticIntString.NUM];
//按钮组
ButtonGroup bg=new ButtonGroup();
//提示选择姓名并输入金额
JLabel jl_inputTips=new JLabel(StaticIntString.INPUT_TIPS1);
//输入押注金额
JTextField jtf_cost=new JTextField(10);
JLabel jl_winFailTips=new JLabel("本次输赢:");
JLabel jl_winFail=new JLabel(StaticIntString.WIN_FAIL);
//本金提示
JLabel jl_ownMoneyTips=new JLabel("我的本金:");
static Properties pro=new Properties();
//从属性文件里读取本金
static ResourceBundle resource=ResourceBundle.getBundle("runningGame.infos");
String ownMoney=resource.getString("ownMoney");
BigInteger bi_times=new BigInteger(resource.getString("times"));
static BigInteger bi_bankruptcy=new BigInteger(resource.getString("bankruptcy"));
String ownMoney_System=resource.getString("ownMoney_System");
//本金
JLabel jl_ownMoney=new JLabel(ownMoney);
//开始按钮
JButton jbt_start=new JButton("开始");
//重新开始按钮
JButton jbt_restart=new JButton("重新开始");
static String selectedName;
RunningMan[] mans=new RunningMan[StaticIntString.NUM]; public GameJFrame() {
if(bi_times.toString().equals("1")){
JOptionPane.showMessageDialog(this, "首次登陆,欢迎光临!\n系统赠予您10000元,\n祝您玩得开心愉快!\n只是玩玩,不要沉溺赌博哦");
}else{
JOptionPane.showMessageDialog(this, "您这是第 "+bi_times.toString()+" 次登陆,欢迎光临!\n祝您玩得开心愉快!\n只是玩玩,不要沉溺赌博哦");
}
bi_times=bi_times.add(new BigInteger("1"));
try {
BufferedInputStream fis=new BufferedInputStream(new FileInputStream("src//runningGame//infos.properties"));
BufferedOutputStream fos=new BufferedOutputStream(new FileOutputStream("src//runningGame//infos.properties"));
String ownMoney_System=resource.getString("ownMoney_System");;
try {
pro.load(fis);
} catch (IOException e1) {
e1.printStackTrace();
}
pro.setProperty("times", bi_times.toString());
pro.setProperty("ownMoney", ownMoney);
pro.setProperty("bankruptcy", bi_bankruptcy.toString());
pro.setProperty("ownMoney_System", ownMoney_System);
try {
pro.store(fos, "");
fis.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} for(int i=0;i<StaticIntString.NUM;i++){
img_back[i]=Toolkit.getDefaultToolkit().createImage("imgBack//"+(i+1)+".jpg");
img_ready[i]=Toolkit.getDefaultToolkit().createImage("imgReady//"+(i+1)+"2.gif");
img_run[i]=Toolkit.getDefaultToolkit().createImage("imgRun//"+(i+1)+"1.gif");
jrb_mans[i]=new JRadioButton(StaticIntString.NAMES[i]);
bg.add(jrb_mans[i]);
jp_control.add(jrb_mans[i]);
}
jbt_start.addActionListener(new ActionListener(){
boolean isSelected=false;
public boolean judgeSelected(){
for(JRadioButton j:jrb_mans){
if(j.isSelected()){
isSelected=true;
}
}
return isSelected;
} @Override
public void actionPerformed(ActionEvent arg0) {
if(!judgeSelected()){
JOptionPane.showMessageDialog(GameJFrame.this, "您还没选人呢",
"看着点", JOptionPane.WARNING_MESSAGE);
return;
}
if(jtf_cost.getText().trim().length()==0){
JOptionPane.showMessageDialog(GameJFrame.this, "您还没下注呢",
"看着点", JOptionPane.WARNING_MESSAGE);
return;
}
char[] cs=jtf_cost.getText().toCharArray();
for(int i=0;i<cs.length;i++){
if(cs[i]<'0' || cs[i]>'9'){
JOptionPane.showMessageDialog(GameJFrame.this, "您输入的不是数字",
"看着点", JOptionPane.WARNING_MESSAGE);
jtf_cost.setText("");
return;
}
if(cs[0]=='0'){
JOptionPane.showMessageDialog(GameJFrame.this, "数字首位不能是0",
"看着点", JOptionPane.WARNING_MESSAGE);
jtf_cost.setText("");
return;
}
}
BigInteger bi_jtf_cost=new BigInteger(jtf_cost.getText());
BigInteger bi_jl_ownMoney=new BigInteger(jl_ownMoney.getText()); if((bi_jtf_cost.compareTo(bi_jl_ownMoney))>0){
JOptionPane.showMessageDialog(GameJFrame.this, "您的下注金额不能超过本金哦",
"看着点", JOptionPane.WARNING_MESSAGE);
jtf_cost.setText("");
return;
} for(JRadioButton j:jrb_mans){
if(j.isSelected()){
selectedName=j.getText();
break;
}
}
for(JRadioButton j:jrb_mans){
j.setEnabled(false);
} jtf_cost.setEditable(false);
jl_inputTips.setText(StaticIntString.INPUT_TIPS2);
jbt_restart.setEnabled(true);
jbt_start.setEnabled(false);
RunningMan.isEnd=false;
RunningMan.canRun=true;
RunningMan.num=0;
for(int i=0;i<StaticIntString.NUM;i++){
mans[i].img=img_run[i];
mans[i].start();
}
}
});
jbt_restart.addActionListener(new ActionListener(){ @Override
public void actionPerformed(ActionEvent arg0) { for(int i=0;i<StaticIntString.NUM;i++){
jrb_mans[i].setText(StaticIntString.NAMES[i]);
jrb_mans[i].setEnabled(true);
}
jl_inputTips.setText(StaticIntString.INPUT_TIPS1);
jtf_cost.setText("");
jtf_cost.setEditable(true);
jl_winFail.setForeground(Color.BLACK);
jl_winFail.setText(StaticIntString.WIN_FAIL);
jbt_start.setEnabled(true);
jbt_restart.setEnabled(false);
RunningMan.isEnd=true;
RunningMan.canRun=false;
bg.clearSelection();
for(int i=0;i<StaticIntString.NUM;i++){
mans[i]=new RunningMan(StaticIntString.NAMES[i], 0, (jp_game.getHeight()*i)/4+30, img_ready[i], GameJFrame.this);
}
}
}); jp_control.setBorder(BorderFactory.createTitledBorder("游戏控制系统"));
jp_control.add(jl_inputTips);
jp_control.add(jtf_cost);
jp_control.add(jl_winFailTips);
jp_control.add(jl_winFail);
jp_control.add(jl_ownMoneyTips);
jp_control.add(jl_ownMoney);
jp_control.add(jbt_start);
jp_control.add(jbt_restart);
this.add(jp_game,BorderLayout.CENTER);
this.add(jp_control, BorderLayout.SOUTH);
setResizable(false);
setTitle("赛跑游戏 ---作者:李章勇");
setBounds(200, 100, 1000, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
for(int i=0;i<StaticIntString.NUM;i++){
mans[i]=new RunningMan(StaticIntString.NAMES[i], 0, (jp_game.getHeight()*i)/4+30, img_ready[i], this);
}
} class GamePanel extends JPanel{
@Override
public void paint(Graphics g) {
super.paint(g);
for(int i=0;i<StaticIntString.NUM;i++){
g.drawImage(img_back[i], 0, (this.getHeight()*i)/4,this.getWidth(),this.getHeight()/4+30,this);
mans[i].drawSelf(g, this); }
g.setColor(Color.RED);
g.fillRect(850, 0, 5, this.getHeight());
}
} public static void main(String[] args) {
new GameJFrame();
}
}

Step 2

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

package runningGame;

public interface StaticIntString {
public static final int NUM=4;
public static final String[] NAMES={ "1号选手", "2号选手", "3号选手", "4号选手" };
public static final String[] WINS={ "预测未来的最好方法,就是创造未来.", "人生重要的不是所站的位置,而是所朝的方向.",
"如你想要拥有完美无暇的友谊,可能一辈子找不到兄弟姐妹","正因年轻咱们一无所有,也正正因年轻咱们将拥有一切." };
public static final String INPUT_TIPS1="请选择赛手并输入金额:";
public static final String INPUT_TIPS2="本次下注金额:";
public static final String GET_WIN="[获胜]";
public static final String WIN_FAIL="[Win/Fail]";
public static final String WIN_STATE="[Win]";
public static final String FAIL_STATE="[Fail]";
} 
属性文件infos.properties: 
#破产次数,登录次数,系统默认赠予的本金,用户的实际本金;只要用户本金小于等于0,系统会自动为用户赠予初始本金。
#Fri Dec 01 09:34:34 CST 2017
bankruptcy=0
times=1
ownMoney_System=10000
ownMoney=10000  
赛手类RunningMan: 
package runningGame;

import java.awt.Graphics;
import java.awt.Image;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Random; import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton; /**
* 赛手的属性:姓名,坐标(x/y),自身图像,准备状态的图像,关联的窗体
* 位移所需的随机数Random,
* 第一名NO1
* 是否能跑的状态canRun
* 比赛是否结束isEnd
* 每个赛手跑完时计数num
*
* 赛手画自己的方法drawSelf
* 赛手跑步位移的方法move
* 子线程运行的run方法
*
* @author 李章勇
*
*/
public class RunningMan extends Thread {
public String name;
private int x_point,y_poinit;
public Image img;
private Image imgReady;
private GameJFrame jf_game;
static Random rand=new Random();
static RunningMan NO1;
static boolean canRun=true;
static boolean isEnd=false;
static int num=0;
static BigInteger bi_ownMoney; public RunningMan(String name,int x_point,int y_point,Image img,GameJFrame jf_game) {
this.name=name;
this.x_point=x_point;
this.y_poinit=y_point;
this.img=img;
this.imgReady=img;
this.jf_game=jf_game;
} public void setName2(String name){
this.name=name;
}
public String getName2(){
return name;
} public void drawSelf(Graphics g,JPanel jp){
g.drawImage(img, x_point, y_poinit, jp);
} public void move(){
x_point+=10+rand.nextInt(30);
} @Override
public void run() {
while(x_point<=850 && canRun){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
move();
}
synchronized(String.class){
if(canRun){
x_point=850;
img=imgReady;
num++;
}
if(!isEnd){
NO1=this;
isEnd=true;
}
if(num==4){
System.out.println("本次比赛第一名:"+NO1.name);
//根据比赛结果,修改金额 类
bi_ownMoney=new GetResult(jf_game).getRightMoney();
new WinDialog();
try {
BufferedInputStream fis = new BufferedInputStream(new FileInputStream("src//runningGame//infos.properties"));
BufferedOutputStream fos=new BufferedOutputStream(new FileOutputStream("src//runningGame//infos.properties"));
try {
GameJFrame.pro.load(fis);
if((bi_ownMoney.compareTo(new BigInteger("0"))<=0)){
JOptionPane.showMessageDialog(jf_game, "您已没有本金,\n系统不差钱儿,再次赠予您 10000 元!\n祝您玩得开心哦!",
"看着点", JOptionPane.WARNING_MESSAGE);
jf_game.jl_ownMoney.setText(GameJFrame.resource.getString("ownMoney_System"));
GameJFrame.pro.setProperty("ownMoney", GameJFrame.resource.getString("ownMoney_System"));
BigInteger bi_bankruptcy=new BigInteger(GameJFrame.resource.getString("bankruptcy")).add(new BigInteger("1"));
GameJFrame.pro.setProperty("bankruptcy", bi_bankruptcy.toString()); }else{
jf_game.jl_ownMoney.setText(bi_ownMoney.toString());
GameJFrame.pro.setProperty("ownMoney", bi_ownMoney.toString());
}
GameJFrame.pro.store(fos, "");
fis.close();
fos.close();
} catch (IOException e1) {
e1.printStackTrace();
}
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
for(JRadioButton j:GameJFrame.jrb_mans){
if(NO1.name.equals(j.getText())){
j.setText(j.getText()+StaticIntString.GET_WIN);
}
}
}
}
}
}

 刷新用户本金的类: 

package runningGame;

import java.awt.Color;
import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger; import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JRadioButton;
import javax.swing.JTextField; /**
* 需要的属性
* 代表四个赛手的按钮
* 输入的金额
* 输赢状态
* 本金
* 关联的窗体
* 获得比赛后、发生变化的钱数getRightMoney
* 设置本金新的数值setNewMoney
* @author 李章勇
*
*/
public class GetResult {
private JRadioButton[] jrb_mans;
private JTextField jtf_cost;
private JLabel jl_winFail;
private JLabel jl_ownMoney; public GetResult(GameJFrame jf_game) {
this.jrb_mans=jf_game.jrb_mans;
this.jtf_cost=jf_game.jtf_cost;
this.jl_winFail=jf_game.jl_winFail;
this.jl_ownMoney=jf_game.jl_ownMoney;
} public BigInteger getRightMoney(){
BigInteger bi_ownMoney=new BigInteger(jl_ownMoney.getText());
BigInteger bi_cost=new BigInteger(jtf_cost.getText());
if(GameJFrame.selectedName!=null && GameJFrame.selectedName.equals(RunningMan.NO1.name)){
jl_winFail.setForeground(Color.GREEN);
jl_winFail.setText(StaticIntString.WIN_STATE);
bi_ownMoney=bi_ownMoney.add(bi_cost);
jl_ownMoney.setText(bi_ownMoney.toString());
}else{
jl_winFail.setForeground(Color.RED);
jl_winFail.setText(StaticIntString.FAIL_STATE);
bi_ownMoney=bi_ownMoney.subtract(bi_cost);
jl_ownMoney.setText(bi_ownMoney.toString());
}
return bi_ownMoney;
}
}

  弹出庆祝框的类WinDialog:

package runningGame;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.util.Random; import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* 对话框背景图
* 4个赛手获胜时的图片
* 自定义面板
* 随机数,随机获取胜利宣言
* @author 李章勇
*
*/
public class WinDialog extends JDialog{
Image img_back=Toolkit.getDefaultToolkit().createImage("imgWin//winbg.jpg");
Image[] img_wins=new Image[StaticIntString.NUM];
WinJPanel wp=new WinJPanel();
Random rand=new Random();
int num=0; public WinDialog() {
for(int i=0;i<img_wins.length;i++){
img_wins[i]=Toolkit.getDefaultToolkit().createImage("imgWin//"+(i+1)+"3.gif");
}
wp.setBounds(100, 100, 400, 300);
add(wp);
setTitle("胜利墙");
setBounds(300, 300, 400, 300);
setResizable(false);
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setVisible(true);
num=rand.nextInt(4);
} class WinJPanel extends JPanel{ @Override
public void paint(Graphics g) {
super.paint(g);
g.drawImage(img_back, 0, 0, this.getWidth(), this.getHeight(), this); switch(RunningMan.NO1.name){
case "1号选手":
g.drawImage(img_wins[0], 50, 100, this);
break;
case "2号选手":
g.drawImage(img_wins[1], 50, 100, this);
break;
case "3号选手":
g.drawImage(img_wins[2], 50, 100, this);
break;
case "4号选手":
g.drawImage(img_wins[3], 50, 100, this);
break;
default:
break;
}
g.setColor(Color.RED);
g.drawString("本次获胜选手:"+RunningMan.NO1.name, 20, 30);
g.drawString(StaticIntString.WINS[num], 20, 50);
}
}
}

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

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

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

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

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

Java多线程之赛跑游戏的更多相关文章

  1. Java多线程之赛跑游戏(含生成exe文件)

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

  2. Java多线程开发系列之四:玩转多线程(线程的控制2)

    在上节的线程控制(详情点击这里)中,我们讲解了线程的等待join().守护线程.本节我们将会把剩下的线程控制内容一并讲完,主要内容有线程的睡眠.让步.优先级.挂起和恢复.停止等. 废话不多说,我们直接 ...

  3. Java多线程编程详解

    转自:http://programming.iteye.com/blog/158568 线程的同步 由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题.Ja ...

  4. 关于JAVA多线程的那些事__初心者

    前言 其实事情的经过也许会复杂了点,这事还得从两个月前开始说.那天,我果断不干IT支援.那天,我立志要做一个真正的程序猿.那天,我26岁11个月.那天,我开始看Android.那天,我一边叨念着有朋自 ...

  5. java多线程学习笔记——详细

    一.线程类  1.新建状态(New):新创建了一个线程对象.        2.就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中, ...

  6. Java 多线程入门

    进程与线程 在学习Java多线程之前,先简单复习一下进程与线程的知识. 进程:进程是系统进行资源分配和调度的基本单位,可以将进程理解为一个正在执行的程序,比如一款游戏. 线程:线程是程序执行的最小单位 ...

  7. Rhythmk 一步一步学 JAVA (21) JAVA 多线程

    1.JAVA多线程简单示例 1.1 .Thread  集成接口 Runnable 1.2 .线程状态,可以通过  Thread.getState()获取线程状态: New (新创建) Runnable ...

  8. JAVA多线程提高十:同步工具CyclicBarrier与CountDownLatch

    今天继续学习其它的同步工具:CyclicBarrier与CountDownLatch 一.CyclicBarrier CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公 ...

  9. java多线程那点事

    屌丝程序员们对自己的技术能力总是毫不掩饰的高调,更有甚者每当完成一个简单的功能或算法实现,恨不得从工位上跳起来,生怕谁不知道一样,心情能理解,但个人完全鄙视这种行为.说到底,大家日常的coding,大 ...

随机推荐

  1. SpringMVC 表单验证

    SpringMVC 表单验证 本章节内容很丰富,主要有基本的表单操作,数据的格式化,数据的校验,以及提示信息的国际化等实用技能. 首先看效果图 项目结构图 接下来用代码重点学习SpringMVC的表单 ...

  2. 用原型代替PRD时,原型应该包含哪些内容

    随着互联网节奏越来越快,传统的需求文档已经比较难适应市场的脚步,特别对于要求敏捷的团队来说,冗余而细致入微的需求文档已经成为包袱(这么长个文档领导也不会看呀).目前大多数团队更喜爱直接使用原型来代替需 ...

  3. Javascript CustomEvent

    Javascript CustomEvent 原文链接 https://davidwalsh.name/customevent,看到一篇介绍自定义事件的文章 翻译一下,不足之处,还请指正. 自浏览器诞 ...

  4. 《Linux命令行与shell脚本编程大全》第十九章 初识sed和gawk

    这两个工具能够极大简化需要进行的数据处理任务. 19.1 文本处理 能轻松实现自动格式化.插入.修改或删除文本元素的简单命令行编辑. sed和gawk就具备上述功能 19.1.1 sed编辑器 被称为 ...

  5. Django 2.0 新特性 抢先看!

    一.Python兼容性 Django 2.0支持Python3.4.3.5和3.6.Django官方强烈推荐每个系列的最新版本. 最重要的是Django 2.0不再支持Python2! Django ...

  6. web管理kvm ,安装webvirtmgr

    原创博文安装配置KVM http://www.cnblogs.com/elvi/p/7718574.htmlweb管理kvm http://www.cnblogs.com/elvi/p/7718582 ...

  7. SubTool 电影字幕下载程序

    项目地址 https://github.com/backtracker/SubTool 程序说明 作为一个高清电影爱好者,找字幕的痛苦懂的人自然会懂.我在网上找了很久,并没有找到好用的字幕下载程序,于 ...

  8. 一些内存模型、并发、netty知识点的记录

    happens-before:描述内存可见性as-if-serial:无论怎么重排序,程序的运行结果不会改变 ReentrantLock依赖了队列同步器AQS,其实现方式是volatile变量的读写操 ...

  9. 基于Java使用Snmp4j进行监控与采集(snmptrap、snmpwalk、snmpget)

    之前有在弄监控服务器这块的工作,今天来整体总结下.因为有些服务器(路由器.交换机等都是基于snmp协议的)必须使用snmp协议去监控采集和接收信息,所以必须去了解snmp相关内容,以及如何在基于jav ...

  10. JSONPath使用

    JSONPath是fastjson在1.2.0之后支持的.JSONPath是一个很强大的功能.关于JSONPath的介绍请查看官方文档 JSONPath. 官方文档上给出了详细的说明以及使用.但是官方 ...