多线程学习(十一)

仿真任务

装饰花园

在这个仿真程序中花园委员会想统计每天通过多个门,进入花园的人数,每个门上有个十字转门相当于是计数器。转动任意一扇门就表示公园的分享计数值就会增加一。

代码如下:

计数器:

/**
 * 计数器
 *
 */
public class Counter {
	private int value;
	private Random random = new Random(47);

	public synchronized int increment() {
		if (random.nextBoolean())
			Thread.yield();// 给个机会让它切换线程
		return ++value;
	}

	public synchronized int getValue() {
		return value;
	}
}

入口:

public class Entrance implements Runnable {
	private static Counter counter = new Counter();
	private static ArrayList<Entrance> stores = new ArrayList<>();
	private int num;
	private final int id;
	private static volatile boolean canceled = false;

	public Entrance(int id) {
		super();
		this.id = id;
		stores.add(this);
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (!canceled) {
			synchronized (this) {
				++num;
			}

			System.out.println(this + " total:" + counter.increment());
			try {
				TimeUnit.MILLISECONDS.sleep(300);// 模拟一下 不要一直 递增
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
		System.out.println("stop:("+id+") num:"+num);
	}

	@Override
	public synchronized String toString() {
		return "Entrance (" + id + ") num:" + num;
	}

	public static int getTotal() {
		return counter.getValue();
	}

	public static int sum() {
		int sums = 0;
		for (Entrance e : stores) {
			sums += e.num;
		}
		return sums;
	}

	public static void cancel() {
		canceled = true;
		/**
		 * 看过一些资料说对原始类型不包括(long,double)变量进行赋值是原子操作
		 * d对引用变量的赋值操作是否是原子操作见:https://www.zhihu.com/question/46681046 第二个回答
		 * 
		 */
	}
}

花园仿真类:

public class Garden {
	public static void main(String[] args) {
		ExecutorService exec = Executors.newCachedThreadPool();
		for (int a = 0; a < 5; a++) {
			exec.execute(new Entrance(a));
		}

		try {
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		Entrance.cancel();

		exec.shutdown();
		boolean flag = false;
		try {
			flag = exec.awaitTermination(2000, TimeUnit.MILLISECONDS);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if (!flag)
			System.out.println("some task don't over.");

		System.out.println("total:" + Entrance.getTotal());
		System.out.println(" sums:" + Entrance.sum());
	}
}

运行结果:

可以删除上面的程序中的 任意 同步代码块 的 同步修饰 就可以看到程序运行失败的效果。
程序中 exec.awaitTermination(2000, TimeUnit.MILLISECONDS); 这个方法的意思 是 executorService 在指定的时间中任务全部停止完毕的话 会返回true。否则返回false.

原文地址:https://www.cnblogs.com/joeCqupt/p/6832998.html