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;

/**
 * 裝飾性花園
 * 
 * 在這個仿真程序中,花園委員會希望瞭解每天通過多個大門進入公共的總人數。
 * 每個大門都有一個十字轉門或某種其他形式的計數器,並且任何一個十字轉門
 * 的計數值遞增時,就表示公園中的總人數的共享計數值也會遞增。
 * 
 * @create @author Henry @date 2016-12-06
 * 
 */

/**
 * 這裏使用單個的Count對象來跟蹤還原參觀者的主計數值,並且將其當作Entrance類中的一個
 * 靜態域進行存儲。Count.increment()和Count.value()都是synchronized的,
 * 用來控制對count域的訪問。
 * 
 * @create @author Henry @date 2016-12-06
 */
class Count {
	private int count = 0;
	private Random rand = new Random(47);
	
	/**
	 * increment()方法使用了Random對象,
	 * 目的是從把count讀取到temp中,到遞增temp並將其存儲回count的這段時間裏,
	 * 有大約一半的時間產生讓步。
	 * 如果你將increment()上的synchronized關鍵字註釋掉,那麼這個程序就會崩潰,
	 * 因爲多個任務將同時訪問並修改count(yield()會使問題更快地發生)
	 * @create @author Henry @date 2016-12-06
	 * 
	 * @return
	 */
	// Remove the synchronized keyword to see counting fail:
	public synchronized int increment() {
		int temp = count;
		if (rand.nextBoolean())// Yield half the time
			Thread.yield();
		return (count = ++temp);
	}

	public synchronized int value() {
		return count;
	}
}
/**
 * Entrance類中的有一個Count對象做爲靜態域進行存儲。
 * 每個Entrance任務都維護着一個本地值number,它包含通過某個特定入口進入的參觀者的
 * 數量。這提供了對count對象的雙重檢查,以確保其記錄的參觀者數量是正確的。Entrance.run()
 * 只是遞增number和count對象,然後休眠100毫秒。
 * 因爲Entrance.canceled是一個volatile布爾標誌,而它只會被讀取和賦值
 * (不會與其他域組合在一起唄讀取),所以不需要同步對其的訪問,就可以安全地操作它。
 * 如果你對諸如此類的情況有任何疑慮,那麼最好總是使用synchronized。
 * 
 * @create @author Henry @date 2016-12-06
 *
 */
class Entrance implements Runnable {
	private static Count count = new Count();
	private static List<Entrance> entrances = new ArrayList<Entrance>();
	private int number = 0;
	// Doesn't need synchronization to read:
	private final int id;
	private static volatile boolean canceled = false;

	// Atomic operation on a volatile field:
	public static void cancel() {
		canceled = true;
	}

	public Entrance(int id) {
		this.id = id;
		// Keep this task in a list. Also prevents
		// garbage collection of dead tasks:
		entrances.add(this);
	}

	@Override
	public void run() {
		while (!canceled) {
			synchronized (this) {
				++number;
			}
			System.out.println(this + " Total: " + count.increment());
			try {
				TimeUnit.MILLISECONDS.sleep(100);
			} catch (InterruptedException e) {
				System.out.println("sleep interrupted");
			}
		}
		System.out.println("Stopping " + this);
	}

	public synchronized int getValue() {
		return number;
	}

	@Override
	public String toString() {
		return "Entrance " + id + ": " + getValue();
	}
	
	public static int getTotalCount(){
		return count.value();
	}
	
	public static int sumEntrances(){
		int sum=0;
		for (Entrance entrance : entrances)
			sum+=entrance.getValue();
		return sum;
	}
}
/**
 * 這個程序在以穩定的方式關閉所有事物方面還有一些小麻煩,其部分原因是爲了說明在終止
 * 多線程程序時你必須相當小心,而另一部分原因是爲了演示interrupt()值,稍後你將學習
 * 有關這個值的知識。
 * 
 * 在3秒鐘之後,main()向Entrance發送static cancel()消息,然後調用exec對象的
 * shutdown()方法,之後調用exec上的awaitTermination()方法。
 * ExecutorService.awaitTermination()等待每個任務結束,如果所有的任務在超時時間到達
 * 之前全部結束,則返回true,否則返回false,表示不是所有的任務都已經結束了。儘管這會導致
 * 每個任務都退出其run()方法,並因此作爲任務而終止,但是Entrance對象仍舊是有效的,
 * 因爲在構造器中,每個Entrance對象都存儲在稱爲entrances的靜態List<Entrance>中。
 * 因此,sumEntrances()仍舊可以作用月這些有效的Entrance對象。
 * 
 * 當這個程序運行時,你將看到,在人們通過十字轉門時,將顯示總人數和通過每個入口的人數。
 * 如果移除Count.increment()上面的synchronized聲明,你將會注意到總人數與你的期望有差異,
 * 每個十字轉門統計的人數將與count中的值不同。只要用互斥來同步對Count的訪問,問題就可以解決了
 * 請記住,Count.increment()通過使用temp和yield(),增加了失敗的可能性。在真正的
 * 線程問題中,失敗的可能性從統計學角度可能非常小,因此你可能很容易就掉進了輕信所有事物都將正確
 * 工作的陷阱裏。就像在上面的示例中,有些還未發生問題就有可能會隱藏起來,因此在複審併發代碼時,
 * 要格外地仔細。
 * 
 * 
 * 
 * @create @author Henry @date 2016-12-06
 */
public class OrnamentalGarden {
	public static void main(String[] args) throws Exception {
		ExecutorService exec=Executors.newCachedThreadPool();
		for (int i = 0; i < 5; i++)
			exec.execute(new Entrance(i));
		TimeUnit.SECONDS.sleep(3);
		
		Entrance.cancel();
		exec.shutdown();
		
		if(!exec.awaitTermination(250, TimeUnit.MILLISECONDS))
			System.out.println("Some tasks were not teminated");
		System.out.println("Total: "+Entrance.getTotalCount());
		System.out.println("Sum of Entrances:"+Entrance.sumEntrances());
		
	}
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章