## 線程的交互
線程的特點是共享進程的資源,內存的存儲空間,但是CPU在某一時刻只能供一個線程占用,由于存在這樣的情況,所以,線程的運行有一些比較難控制的地方,當多個線程都想占用CPU的時候就需要來一場決斗決定那一個線程占用CPU了,否則線程世界就混亂了,當然,處理的方式有好多種,和我們人類世界一樣,弱肉強食,分成三六九等依次占用,或者先到先得
~~~java
/**
* 宇宙的能量系統
* 遵循能量守恒定律:
* 能量不會憑空創生或消失,只會從一處轉移到另一處
*/
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關鍵字實現互斥行為
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.print(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;
}
}
~~~
~~~java
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();
}
}
}
~~~
~~~java
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();
}
}
}
~~~
### 爭用條件指:
當多個線程同時共享訪問同一數據(內存區域)時,每個線程都嘗試操作該數據,從而導致數據被破壞的現象,這是應該避免的事情,所以,就產生了線程世界中的優先級的各種算法,比如:先到先得、優先級、輪詢等等。
### 互斥的實現:
synchronized(lockObj);java的語法保證的同一時間,只有一個線程獲得lockObj
### 同步:
wait(),notify(),notifyall(),都是屬于object類,并不是thread類
### wait set
類似于線程的休息室,訪問共享數據的代碼稱為critical section。一個線程獲取鎖,然后進入臨界區 ,發現某些條件不滿足,然后調用鎖對象上的wait方法,然后線程釋放掉鎖資源,進入鎖對象上的wait set。其他線程可以獲取所資源,然后執行,完了以后調用notify,通知鎖對象上的等待線程。
Ps:若調用notify();則隨機拿出(這隨機拿出是內部的算法,無需了解)一條在等待的資源進行準備進入Critical Section;若調用notifyAll();則全部取出進行準備進入Critical Section。
1、Java Memory Mode:JMM描述了java線程如何通過內存進行交互,了解happens-before,synchronized,voliatile & final
2、Locks % Condition:鎖機制和等待條件的高層實現 java.util,concurrent.locks
3、線程安全性:原子性與可見性,死鎖等
4、多線程常用的交互模型
· Producer-Consumer模型
· Read-Write Lock模型
· Future模型
· Worker Thread模型
5、Java5中并發編程工具:java.util.concurrent 線程池ExcutorService Callable&Future BlockingQueue
6、推薦書本:CoreJava & JavaConcurrency In Practice