多線程管理
- 線程類
–通過繼承Thread或實現Runable
– 通過start方法,調用run方法,run方法工作
– 線程run結束後,線程退出 - 粗粒度: 子線程與子線程之間、和main線程之間缺乏同步
- 細粒度:線程之間有同步協作
– 等待
– 通知/喚醒
– 終止- 等待:等A線程執行到某一個地方的時候,B線程告A線程,讓A等待一會,等A到了,在往下一起走
- 通知/喚醒: A到了,A告訴B,我到了,可以走了
- 線程狀態
– NEW 剛創建(new)
– RUNNABLE 就緒態(start)
– RUNNING 運行中(run)
– BLOCK 阻塞(sleep)
– TERMINATED 結束
- Thread的部分API已經廢棄
– 暫停和恢復spspend/resume (這些方法很危險,已經廢棄,不建議使用)
– 消亡 stop/destroy (這些方法很危險,已經廢棄,不建議使用) - 線程阻塞/和喚醒
– sleep,時間一到,自己會醒來
– wait/notify/notifyAll 等待,需要別人來喚醒
– join 等待另外一個線程結束
– interrupt 向另外一個線程發送中斷信號,該線程收到信號,會觸發InterruptedException(可解除阻塞),並進行下一步處理- wait: 休眠狀態,等別的線程調用notify或者notifyAll的時候,可以醒來。一個等待(wait)的線程是需要其他線程去喚醒的,如果沒有其他線程去喚醒它,那這個線程就一直等待,一直處於休眠狀態
生產者/消費者示例:
經典生成者與消費者問題
生產者不斷的往倉庫中存放產品,消費者從倉庫中消費產品。
其中生產者和消費者都可以有若干個。
倉庫規則:容量有限,庫滿時不能存放,庫空時不能取產品。
源碼示例:
//產品
public class Product {
private Integer id;
private String name;
}
package product;
/**
* @ClassName:Storage
* @Description:倉庫類
* @author: Torey
*/
public class Storage {
//倉庫容量
public Storage(Integer volume) {
this.products = new Product[volume];
this.volume=volume;
}
//倉庫容量
private Integer volume;
public Integer getVolume() {
return volume;
}
public void setVolume(Integer volume) {
this.volume = volume;
}
//倉庫容量
private Product[] products ;
private int top = 0;
//生產者向倉庫中放入產品
public synchronized void push(Product product){
while (top == products.length) {
try {
System.out.println("product wait");
wait();//倉庫已滿,等待
}catch (Exception ex){
ex.printStackTrace();
}
}
//把產品放入倉庫
products[top++]=product;
System.out.println("producer notifyAll"+Thread.currentThread().getName() + "生產了產品:"+product);
notifyAll();//喚醒等待線程
}
//消費者從倉庫中取出產品
public synchronized Product pop() {
while (top == 0) {
try{
System.out.println("empty! consumer wait");
wait();}catch (Exception ex){
ex.printStackTrace();
}
}
//從倉庫中取產品
--top;
Product p = new Product(products[top].getId(), products[top].getName());
products[top]=null;
System.out.println("comsumer notifyAll "+Thread.currentThread().getName() + " 消費了產品:" + p);
notifyAll(); //喚醒等待的線程
return p;
}
}
package product;
/**
* @ClassName:Consumer
* @Description:消費者
* @author: Torey
*/
public class Consumer implements Runnable {
private Storage storage;
/**
*
* @param storage 倉庫
* @param interval 多久消費一個
*/
public Consumer(Storage storage,Integer interval) {
this.storage = storage;
this.integer=interval*1000;
}
private Integer integer;
@Override
public void run() {
int i=0;
while (true){
try {
i++;
storage.pop();
Thread.sleep(integer);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
package product;
import java.util.Random;
/**
* @ClassName:Producer
* @Description:生產者
* @author: Torey
*/
public class Producer implements Runnable {
private Storage storage;
/**
*
* @param storage 倉庫
* @param integer 多久生產一個
*/
public Producer(Storage storage,Integer integer) {
this.storage = storage;
this.integer=integer*1000;
}
private Integer integer;
@Override
public void run() {
int i=0;
Random r = new Random();
while (true){
i++;
Product product = new Product(i, "電話" + r.nextInt(100));
try {
Thread.sleep(integer);
storage.push(product);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
package product;
/**
* @ClassName:ProductTest
* @Description:
* 經典生成者與消費者問題
* 生產者不斷的往倉庫中存放產品,消費者從倉庫中消費產品。
* 其中生產者和消費者都可以有若干個。
* 倉庫規則:容量有限,庫滿時不能存放,庫空時不能取產品。
* @author: Torey
*/
public class ProductTest {
public static void main(String[] args) throws InterruptedException {
//倉庫容量爲 5個
Storage storage = new Storage(5);
//每5秒鐘消費一次
new Thread(new Consumer(storage,5),"消費者1").start();
//每秒生產一個
new Thread(new Producer(storage,1),"生產者2").start();
}
}