Java5的java.util.concurrent包下引入了大量的用于解决并发问题的新类;相对于前面那些基础的线程同步和通信的方法,这些新类是一种更高层次上的抽象,使用起来还是比较容易的.这篇博客就来学习其中的两个新类:CountDownLatch和CyclicBarrier;并使用CyclicBarrier来模拟一个简单的赛马游戏.

一.CountDownLatch

使用CountDownLatch对象时,我们需要给其设定一个初始的计数值,然后在这个对象上调用await()的任务都会阻塞,直到这个对象的计数值减为0;其它的任务可以在完成自己的工作时调用这个对象的countDown()方法来减少这个对象的计数值。所以这个类可以用于同步一个或多个任务,强制它们等待由其它任务执行的一组操作完成;一个典型的应用场景是将一个程序分解为n个互相独立的可解决任务,并创建值为n的CountDownLatch,当每个任务完成时,就会在这个对象上调用countDown().而那些等待这个问题被解决的任务在这个对象上调用await(),使自己阻塞,直到这个对象计数值减为0;另外值得注意的一点是这个对象并不会协调n个任务执行的先后顺序。下面演示这种技术的一个框架示例:

package lkl;

import java.util.Random;

import java.util.concurrent.CountDownLatch;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.TimeUnit;

/** * CountDownLatch用来同步一个或多个任务,强制它们 * 等待由其它任务执行的一组操作完成 * */

//预先执行的任务

class TaskPortion implements Runnable{

private static int counter = 0;

private final int id= counter++;

//全局多个线程共享一个Random对象,这里其实牵涉到一个并发问题

//只是实际上Random.next()本身就是线程安全的,所以不需要我们自己进行同步

private static Random rand = new Random(47);

private final CountDownLatch latch;

public TaskPortion(CountDownLatch latch){

this.latch = latch;

}

public void run(){

try{

dowork();

latch.countDown(); //减少计数值

}catch(InterruptedException ex){

System.out.println(this+" 通过中断异常退出");

}

}

//线程睡眠一段时间模拟做些工作

public void dowork() throws InterruptedException{

TimeUnit.MILLISECONDS.sleep(rand.nextInt(2000));

System.out.println(this+" completed");

}

public String toString(){

return String.format("%1$-3d", id);

}

}

class WaitingTask implements Runnable{

private static int counter = 0;

private final CountDownLatch latch;

private final int id = counter++;

public WaitingTask(CountDownLatch latch){

this.latch = latch;

}

public void run() {

try{

latch.await();; //在latch上的计数值减为0之前,都会阻塞在这里

System.out.println(this+" completed");

}catch(InterruptedException ex){

System.out.println();

}

}

public String toString(){

return String.format("WatitingTask %1$-3d", id);

}

}

public class CountDownLatchDemo {

static final int SIZE = 100;

public static void main(String[] args) throws Exception{

ExecutorService exec = Executors.newCachedThreadPool();

//所有线程都必须共享一个latch对象

//设定初始计数值为100,即必须等待100个任务完成以后

//在这个对象上调用await()的任务才能执行

CountDownLatch latch = new CountDownLatch(SIZE);

//开10个等待线程

for(int i=0; i<10; i++){

exec.execute(new WaitingTask(latch));

}

//开100个预先执行的线程

for(int i=0; i

exec.execute(new TaskPortion(latch));

}

System.out.println("Latched all takss");

exec.shutdown();

}

}

二.CyclicBarrier

CyclicBarrier适用于这种情况:我们希望创建一组任务,它们并行的执行,然后在进行下一个步骤之前等待,直至所有的任务都完成(按正常的线程调度,这是不可能实现的)。它使得所有任务都在栅栏处列队,因此可以一致的向前移动。这看起来和上面的CountDownLatch类似,但是CountDownLatch只能触发一次事件,而CyclicBarrier可以多次重用.更具体的使用可以描述如下:我们创建一个指定了初始计数值为n和Runnable对象为r的CyclicBarrier对象,然后将其提交给n个线程,每个线程在完成当前的任务后就会调用这个对象上的await()减少计数值并且当前线程会阻塞;这样直到最后一个线程调用了await()使得计数值减为0,然后就会调用这个Cyclibarrier对象上r的run()方法,在run()方法执行完成以后,又会重置CyclicBarrier对象的计数值然后重复上面的过程。通过这样的一个过程,就达到了使多个线程一致向前移动的效果。

下面通过使用这个类仿真一个赛马游戏:

package lkl;

import java.util.ArrayList;

import java.util.List;

import java.util.Random;

import java.util.concurrent.BrokenBarrierException;

import java.util.concurrent.CyclicBarrier;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.TimeUnit;

/** * 模拟赛马游戏 * 下面的程序中使用"*"表示目前马所在的位置,使用"=="表示栅栏 * 具体的思想是:我们使用一个线程来模拟一匹马,在这个线程中我们每次都会 * 生成一个随机数表示本次移动这匹马跑了多少步;然后使用CyclicBarrier来同步多个线程 * 使它们能一致的向前移动,从而产生赛马的效果。我们会在CycylicBarrier的run()方法中 * 打印出每次移动以后的情况。 * 可以通过调整控制台的尺寸大小到只有马,看到这个仿真的效果。 * */

//模拟马的线程

class Horse implements Runnable{

private static int counter = 1;

private final int id = counter++;//马的编号

private int strides = 0; //当前马所走的步数

private static Random rand = new Random(47);

private static CyclicBarrier barrier;//所有线程共享一个CyclicBarrier对象

public Horse(CyclicBarrier b){

barrier = b;

}

//返回当前马所跑的步数

public synchronized int getStrides(){

return strides;

}

public void run(){

try

{

while(!Thread.interrupted()){

synchronized(this){

//本次移动了多少步

strides+=rand.nextInt(3); //0,1,2

}

//阻塞直到最后一个线程也调用了这个方法

//然后就会先执行barrier的run()任务,然后再重置计数值解除线程阻塞,然后调用这些线程

//这样就可以保证每次都是每次都是每个线程都调度一次,然后输出一次当前情况

//然后再进行下一轮的调用,这样就可以模拟赛马的情形了。不然因为操作系统的线程

//调用是不均匀的,是模拟不了的。

barrier.await();

}

}

catch(InterruptedException ex){

System.out.println(this+ " 通过中断异常退出");

}catch(BrokenBarrierException e){//await()引起的异常

throw new RuntimeException();

}

}

public String toString(){

return "Horse "+id+" ";

}

//使用"*"表示当前马的轨迹

public String tracks(){

StringBuilder s = new StringBuilder();

for(int i=0 ;i

s.append("*");

}

s.append(id);

return s.toString();

}

}

public class HorseRace {

static final int FINISH_LINE=75; //终点线步数

private List horses = new ArrayList();

private ExecutorService exec = Executors.newCachedThreadPool();

private CyclicBarrier barrier;

public HorseRace(int nHorse,final int pause){

//构造CyclicBarrier对象时需要传入一个Runnable对象用来计数值减为0的时候

//执行,这里使用匿名内部类的形式传入的。在这里这个Runnable对象负责打印

//出每次所有马都移动一次以后的情况。

barrier = new CyclicBarrier(nHorse,new Runnable(){

public void run(){

StringBuilder s = new StringBuilder();

//表示栅栏

for(int i=0 ; i

s.append("=");

}

System.out.println(s);

//打印每匹马当前的位置(“*”+id表示)

for(Horse horse : horses){

System.out.println(horse.tracks());

}

//如果有那匹马越过终点线,则打印出该匹马获胜

//并结束游戏(结束掉所有的赛马线程)

for(Horse horse: horses){

if(horse.getStrides()>=FINISH_LINE){

System.out.println(horse+" won");

exec.shutdownNow();

return;

}

}

try{

//睡眠一段时间

TimeUnit.MILLISECONDS.sleep(pause);

}catch(InterruptedException ex){

ex.printStackTrace();

}

}

});

//产生nHorse匹马赛跑

for(int i=0; i

Horse horse = new Horse(barrier);

horses.add(horse);

exec.execute(horse);

}

}

public static void main(String[] args){

//默认7匹马赛跑

int nHorses = 7;

int pause = 200;

new HorseRace(nHorses,pause);

}

}

模特赛马java课程设计_Thinking in Java---Concurrent包下的新构件学习+赛马游戏仿真...相关推荐

  1. java 课程设计文本编辑器,JAVA课程设计--文本编辑器

    JAVA课程设计--文本编辑器 Java 语言课程期末作业 1 Java 语言课程期末作业 题 目 第 8 题,文本编辑器 学 院 计算机学院 专 业 计算机科学与技术 班 别 学 号 姓 名 201 ...

  2. java课程设计 考试系统,java课程设计考试系统.

    java课程设计考试系统.Tag内容描述: 1.目 录 第一章第一章 引言引言 3 1 1目的 3 1 2名词解释 3 1 3参考资料 3 1 4文档结构 3 第第 2 章章远景远景 4 2 1项目概 ...

  3. java课程设计数字日历,java课程设计简单日历.doc

    java课程设计简单日历.doc java课程设计报告题目:JAVA简易时间日历程序学生姓名:董兆军学号:2010314120专业班级:信101指导教师:李红强Java课程设计报告信101董兆军201 ...

  4. java课程设计qq,模块java课程设计报告qq聊天

    河南工业大学 课程设 计 课程设计名称: ja  a qq聊天系统 学生姓名 : x  aoy    指导教 师: 王高平 课程设计时间: 2016.7.7 计科 专业课程设计任务书 说明: ...

  5. 人事管理java 课程设计_数据库+Java课程设计 人事管理系统 (一)

    一.JAVA与数据库的合作 此次开发语言为Java,所用的数据库驱动是mysql-connector-java-5.1.8-bin.jar 第一步   用Java连接MySQL数据库(驱动下载:htt ...

  6. 【Java课程设计】基于Java Swing+MySQL的学生基本信息管理系统----附git仓库地址

    一.项目简介 功能描述: 基于Java Swing+MySQL的学生基本信息管理系统,支持对学院.班级.学生信息的增删改查. 参考git地址或博客地址: https://www.bilibili.co ...

  7. 【Java课程设计】基于Java Swing 的图书管理系统

    文章目录 前言 一.功能结构 二.项目预览 三.数据库的设计 四.数据表的设计 五.代码实现 总结 前言

  8. java课程设计象棋_java课程设计 中国象棋

    [实例简介] 内附eclipse项目,可运行jar包,和课程设计报告,觉得让你一下子看懂 [实例截图] [核心代码] P17-象棋java课程设计 └── P17-象棋java课程设计 ├── res ...

  9. Java 课程设计--数据库管理系统

    目录 源代码说明 一.源代码地址 二.源代码文件说明 1.关键类说明 2.关键方法说明 参考文献 源代码说明 该文章是对JAVA课程设计-<基于JAVA实现的数据库管理系统> 的源代码说明 ...

最新文章

  1. 电磁场与电磁波第一章 矢量分析
  2. 也谈.net加密解密
  3. 音视频技术开发周刊(第125期)
  4. webService学习6:解析组件 's:schema' 时出错。在该组件中检测到 's:schem
  5. Wordpress 与 Sphere 结为合作伙伴
  6. Oracle10.2.0.1开始可以在线删除数据文件
  7. 1000道Python题库系列分享五(40道)
  8. Collectors.summingDouble()
  9. [C] 跨平台使用Intrinsic函数范例2——使用SSE2、AVX指令集 处理 双精度浮点数组求和...
  10. Unity3D脚本学习1
  11. 罗辑回归,Logistic Regression(or sigmoid function)
  12. 新鲜出炉!ECCV2022 107个开源数据集合辑,全球 AI 研究热点一网打尽
  13. JAVA组合框怎么添加加减乘除,[C#]组合框设计windows加减乘除简单计算器应用
  14. I/O error on POST request for “http://localhost:9411/api/v2/spans“
  15. 联想Thinkpad重装系统的详细操作指南
  16. 魔方(6)三阶空心魔方、二阶空心魔方
  17. 使用服务网格提升应用和网络安全
  18. About云公益4月名额抽取
  19. 【雷达通信】基于matlab距离角度解耦法MIMO-OFDM雷达波束形成【含Matlab源码 2208期】
  20. 技术视角看我的一码通-系列2

热门文章

  1. Android学习之 Fragment
  2. HTML协议目标端口和源端口,协议:TCP源IP:源端口:80目的IP:目的端口:4049TT? 爱问知识人...
  3. 计算机server无法启动服务,win7不能启动server服务提示错误1068的解决方法
  4. HTML/JSP中一些单书名号标签的用途
  5. 第八章:项目质量管理 - (8.1 规划质量管理)
  6. 编程语言:C语言网络资源
  7. [系统安全] 二十二.PE数字签名之(下)微软证书漏洞CVE-2020-0601复现及Windows验证机制分析
  8. ICD建模功能约束(详见DL/T860.73附录B)
  9. DSP在线升级方案:TMS320C6678使用网络或者串口输出升级数据进行固件升级
  10. Windows系统中如何释放C盘空间