统计花园内每天,每个门进入的人数及总人数.

     首先对于这样的问提,要考虑的就是:  若花园中的任意两个大门在同一时刻分别进入两个人,在花园总计数器上到底是加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> doors = new ArrayList<Doors>();

	/* 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值