博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
统计花园内每天,每个门进入的人数及总人数.
阅读量:7243 次
发布时间:2019-06-29

本文共 4838 字,大约阅读时间需要 16 分钟。

hot3.png

     首先对于这样的问提,要考虑的就是:  若花园中的任意两个大门在同一时刻分别进入两个人,在花园总计数器上到底是加2还是加4?

        我们肯定会不假思索的回答,这TM还要问,肯定是加4啊,是2不就完了嘛. 但是计算机往往就是这样,对人脑来说很简单的操作,对于计算机来说却要大费周折.  结果是:有可能是2(如果在没有任何并发操作的情况下

        有的同学会问,为啥呢?  因为在java中 简单的读取和写入操作 不是原子性操作,也就是说 :获取总计数器的值、将值+2 是两个操作。 所以就会出现 一个门获取总计数器的值0(初始值0)时,还没有完成对其+2的操作,另一个门也获取了总计数器的值,但此时总计数的值还是0,并对其进行+2操作。所以当两个们在完成取指和赋值的操作后,我们看到的总计数器的值却是2。

       所以为了不让  有可能是2, 我们必须对总计数器取值 和 赋值操作进行同步,也就是我们常见的synchronized 关键字、或者使用显示的 Lock 类 对所有与总计数器相关的操作进行同步

以下是我写的一个渣渣代码,仅供参考。

先附上无并发控制的代码和运行结果(注意: 此处没有对公园总人数加上synchronized)

package com.sanmina.threadDemo.synchro;/** * TotalCount.java */import java.util.ArrayList;import java.util.List;import java.util.Random;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;/** * CountMachine 花园总人数计数器 *  * @author mercy_yang * */class CountMachine {	/* totalCount 总计数器的人数 */	private static int totalCount;	public int getTotalCount() {		return totalCount;	}	public void incrementTotal(int person) {		totalCount = totalCount + person;	}	@Override	public String toString() {		return "TOTAL: " + totalCount;	}}/** * Doors 各个门统计本门计入人数 *  * @author mercy_yang * */class Doors implements Runnable {	/* countMachine 花园总人数计数器 */	private CountMachine countMachine;	/* count 这个门进入的总人数 */	private int count = 0;	/* entryPerson 这个门每次的进入的人数 */	private int entryPerson;	/* id 门的标识 */	private int id;	/* rand 产生随机的入门人数 */	private static Random rand = new Random(47);	/* doors 统计所有门 */	private static List
 doors = new ArrayList
(); /* cancel 结束标识,此处必须是volatlie 否则会出现意向不到的结果 */ private volatile static boolean cancel = false; public static void canceled() { cancel = true; } public Doors(int id, CountMachine countMachine) { this.id = id; this.countMachine = countMachine; doors.add(this); } public int getEntry() { return entryPerson; } public synchronized void addCount() { count = count + entryPerson; } public synchronized int getTotal() { return count; } public static int getDoorsCount() { int sum = 0; for (Doors door : doors) { System.out.println(door); sum += door.getTotal(); } return sum; } /**  * 统计每次本门入院的人数 并 在总人数增加  */ @Override public void run() { while (!cancel) { entryPerson = rand.nextInt(5); synchronized (this) { Thread.yield(); if (entryPerson != 0) { addCount(); countMachine.incrementTotal(entryPerson); System.out.println("本次进入 " + entryPerson + "个人 " + this); } } try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } Thread.interrupted(); } System.out.println("Stopping " + this); } @Override public String toString() { return "#Door" + id + ": " + count + " TOTAL: " + countMachine.getTotalCount(); }}public class TotalCount { /* countMachine 唯一的花园总人数计数器 */ private static CountMachine countMachine = new CountMachine(); public static void main(String[] args) throws InterruptedException { ExecutorService exec = Executors.newCachedThreadPool(); /* 定义5个大门 */ for (int i = 0; i < 5; i++) { exec.execute(new Doors(i, countMachine)); } TimeUnit.SECONDS.sleep(1); Doors.canceled(); exec.shutdown(); // 结束 /* 判断所有线程是否运行结束 */ while (Thread.activeCount() > 1) { Thread.yield(); } System.out.println("*********"); System.out.println("所有门总人数和"+Doors.getDoorsCount()); System.out.println("花园总人数: " + countMachine.getTotalCount()); }}

运行结果

本次进入 3个人 #Door0: 3 TOTAL: 3本次进入 1个人 #Door3: 1 TOTAL: 7本次进入 3个人 #Door2: 3 TOTAL: 6本次进入 1个人 #Door4: 1 TOTAL: 8本次进入 4个人 #Door1: 4 TOTAL: 12本次进入 3个人 #Door0: 6 TOTAL: 15本次进入 2个人 #Door3: 3 TOTAL: 17本次进入 2个人 #Door4: 3 TOTAL: 19本次进入 3个人 #Door1: 7 TOTAL: 22本次进入 3个人 #Door0: 9 TOTAL: 25本次进入 1个人 #Door2: 4 TOTAL: 26..............*********#Door0: 22 TOTAL: 98#Door1: 19 TOTAL: 98#Door2: 20 TOTAL: 98#Door3: 18 TOTAL: 98#Door4: 20 TOTAL: 98所有门总人数和:99花园总人数: 98

可以看到, 我对各个们进入的人数进行了并发控制,没有对花园总人数的操作进行并发控制。

所以结果中的花园总人数是98 而 所有们加起来的人数是 99 。明显出现了差异。(注:各人运行的结果可能不同)

现在我为CountMachine 类中的 count 静态变量(此处必须是静态变量) 加上synchronizedr如下(其他不变)

class CountMachine {	/* totalCount 总计数器的人数 */	private static int totalCount;	public synchronized int getTotalCount() {		return totalCount;	}	public synchronized void incrementTotal(int person) {		totalCount = totalCount + person;	}	@Override	public String toString() {		return "TOTAL: " + totalCount;	}}

运行结果

本次进入 3个人 #Door0: 3 TOTAL: 3本次进入 3个人 #Door2: 3 TOTAL: 6本次进入 1个人 #Door3: 1 TOTAL: 7本次进入 1个人 #Door4: 1 TOTAL: 8本次进入 4个人 #Door0: 7 TOTAL: 12本次进入 3个人 #Door1: 3 TOTAL: 15............*********#Door0: 27 TOTAL: 99#Door1: 12 TOTAL: 99#Door2: 20 TOTAL: 99#Door3: 16 TOTAL: 99#Door4: 24 TOTAL: 99所有门人数总和: 99花园总人数: 99

可以看到在 CountMachine 类中的count的 getTotalCount()方法和incrementTotal()方法上加上 synchronized 后  总数就对上了。(可以多次运行,查看总数是否会对不上),当然博主可以保证不会。嘻嘻...

大家可以自己尝试使用Lock类

转载于:https://my.oschina.net/mercyyang/blog/597357

你可能感兴趣的文章
企业服务HR SaaS谁是最强音?三家案例公司告诉你市场真实状况
查看>>
性能为王:SQL标量子查询的优化案例分析
查看>>
SAP孙丽军:用数据技术为体育行业挖掘价值
查看>>
新病毒王“永恒之石”来袭 一次用了7个NSA漏洞
查看>>
软件性能测试过程
查看>>
微服务技术栈2.0
查看>>
光伏能源虚拟货币:互联网+时代的先驱者
查看>>
用大数据改进制造业 必须掌握的3大要领
查看>>
这个僵尸网络自2014年起已经感染了近百万台设备
查看>>
凯萨医疗机构的CIO分享数字化转型经验
查看>>
激光投影企业对会议市场发起魅力攻势
查看>>
WiFi万能钥匙首推WiFi行业安全险
查看>>
负载压力测试中监理的工作重点
查看>>
《拥抱变化——社交网络时代的企业转型之道》一信誉和风险管理
查看>>
09_EGIT插件的安装,Eclipse中克隆(clone),commit,push,pull操作演示
查看>>
《Scala机器学习》一一2.7 总结
查看>>
《编写高质量代码:改善c程序代码的125个建议》——第2章 保持严谨的程序设计,一切从表达式开始做起 建议12:尽量减少使用除法运算与求模运算...
查看>>
nginx error_log 错误日志配置说明
查看>>
编程语言拟人化:Java、C++、Python、Ruby、PHP、C#、JS
查看>>
《BackTrack 5 Cookbook中文版——渗透测试实用技巧荟萃》—第3章3.2节服务遍历
查看>>