多線程的交互
阿新 • • 發佈:2017-08-01
run getname 能量 訪問 try 進入 for循環 ted wid
當多個線程同時共享訪問同一數據時,每個線程都嘗試操作該數據,從而導致改數據被破壞,這種現象稱為爭用條件。
同步的實現:wait(),notify(),notifyAll()
當一個線程要訪問共享資源,首先要拿到鎖後進入臨界區,如果發現某些條件不符合,調用wait方法釋放鎖資源,線程進入鎖對象上的Wait Set,
拿到鎖的當前運行進程執行完時調用notify()會喚醒鎖資源所持有的等待區域中的一條線程(隨機),使該線程有機會競爭CPU資源;
調用notifyAll()會喚醒鎖資源所持有的等待區域中的所有線程,使這些線程有機會競爭CPU資源;
EnergySystem:
/** * 宇宙的能量系統 * 遵循能量守恒定律: * 能量不會憑空創生或消失,只會從一處轉移到另一處 */ public class EnergySystem { //能量盒子,能量存貯的地方 private final double[] energyBoxes; private final Object lockObj = new Object(); /** * * @param n 能量盒子的數量 * @param initialEnergy 每個能量盒子初始含有的能量值*/ public EnergySystem(int n, double initialEnergy){ energyBoxes = new double[n]; for (int i = 0; i < energyBoxes.length; i++) energyBoxes[i] = initialEnergy; } /** * 能量的轉移,從一個盒子到另一個盒子 * @param from 能量源 * @param to 能量終點 *@param amount 能量值 */ public void transfer(int from, int to, double amount){ synchronized(lockObj){ // if (energyBoxes[from] < amount) // return; //while循環,保證條件不滿足時任務都會被條件阻擋 //而不是繼續競爭CPU資源 while (energyBoxes[from] < amount){ try { //條件不滿足, 將當前線程放入Wait Set lockObj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()); energyBoxes[from] -= amount; //System.out.printf("從%d轉移%10.2f單位能量到%d", from, amount, to); energyBoxes[to] += amount; // System.out.printf(" 能量總和:%10.2f%n", getTotalEnergies()); //喚醒所有在lockObj對象上等待的線程 lockObj.notifyAll(); } } // 獲取能量世界的能量總和 public double getTotalEnergies(){ double sum = 0; for (double amount : energyBoxes) sum += amount; return sum; } // 返回能量盒子的長度 public int getBoxAmount(){ return energyBoxes.length; } }
EnergyTransferTask:
public class EnergyTransferTask implements Runnable{ //共享的能量世界 private EnergySystem energySystem; //能量轉移的源能量盒子下標 private int fromBox; //單次能量轉移最大單元 private double maxAmount; //最大休眠時間(毫秒) private int DELAY = 10; public EnergyTransferTask(EnergySystem energySystem, int from, double max){ this.energySystem = energySystem; this.fromBox = from; this.maxAmount = max; } public void run() { try{ while (true){ int toBox = (int) (energySystem.getBoxAmount()* Math.random()); double amount = maxAmount * Math.random(); energySystem.transfer(fromBox, toBox, amount); Thread.sleep((int) (DELAY * Math.random())); } }catch (InterruptedException e){ e.printStackTrace(); } } }
public class EnergySystemTest { //將要構建的能量世界中能量盒子數量 public static final int BOX_AMOUNT = 100; //每個盒子初始能量 public static final double INITIAL_ENERGY = 1000; public static void main(String[] args){ EnergySystem eng = new EnergySystem(BOX_AMOUNT, INITIAL_ENERGY); for (int i = 0; i < BOX_AMOUNT; i++){ EnergyTransferTask task = new EnergyTransferTask(eng, i, INITIAL_ENERGY); Thread t = new Thread(task,"TransferThread_"+i); t.start(); System.out.println(t.activeCount()); } } }EnergySystemTest
輸出結果:
在for循環中from是遞加的,但結果並不是從0,1,2.......按順序轉移?
雖然進程按順序創造task但start方法不會等到run方法執行完就會繼續執行下面的代碼,所以導致創建了很多線程但他們隨機執行run方法。
多線程的交互