1. 程式人生 > >多線程的交互

多線程的交互

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方法。

多線程的交互