java多線程2

12.線程的分類

線程可以分爲用戶線程和守護線程
1)守護線程(daemon thread):是指在後臺運行的線程,用於提供後臺服務
2)用戶線程(user thread):Java創建的線程默認是用戶線程
3)二者差別:
– 當進程中還有用戶線程在運行時,進程是不終止
– 當進程中只有守護線程運行時,進程終止

13.線程的生命週期

當線程被創建啓動之後,不是啓動立刻執行狀態,它不是一直處於執行狀態,它要經歷如下幾個步驟:
新建(New)–就緒(Runnable)–運行(Running)–阻塞(Block)–死亡(Dead),阻塞不一定發生。

1)新建狀態:

當程序創建好一個線程後,該線程就處於新建狀態,此時jvm爲其分配內存。

2)就緒狀態:

當線程對象調用start方法後,該線程處於就緒狀態,處於cpu等待調度運行。

3)運行狀態:

已經開始執行run方法的線程執行體,該線程處於運行狀態,cpu已經調度執行。

4)阻塞的狀態:

當運行狀態的線程失去所佔的資源後,就進入阻塞狀態
– 當線程調用sleep方法時,主動放棄cpu資源。
– 當線程想要獲取同步監視器的時候,此監視器正被其他線程所持有。
– 線程在等待某個通知(notify)

5)死亡狀態:

線程在run方法執行結束後進入死亡狀態。此外如果線程執行了interrupt(),(stop方法已經過時)那麼也會進入死亡狀態。
在這裏插入圖片描述

14.Thread類的常用方法:

1)start():啓動線程並執行相應的run()方法
2)run():子線程需要執行的代碼放入此方法中
3)currentThread():獲取當前線程
4)GetName():可以獲取子線程的名稱
5)SetName():設置子線程的名稱
6)yield():調用此方法的線程釋放cpu的執行權;當一個線程使用了此方法後,就會把自己的cpu執行權交出來,讓自己或者其他線程運行,不是單純的讓給其他線程。
7)join():在子線程1中調用線程2的join(),表示執行到此方法時,線程1阻塞,直到線程2執行完畢,線程1再接着join()方法後的代碼執行。
8)Sleep(long m):1s=1000ms,讓當前線程睡眠
9)isLive():判斷當前進程是否存活
10)優先級(默認值:5,最小值:1,最大值:10)
– getPriority():獲取優先級
– setPriority():設置改變優先級
11)線程通信的方法
– wait():等到,調用此方法的線程釋放共享資源的鎖,然後從運行狀態退出,進入等待隊列,直到被喚醒。
– notify():喚醒等待的線程:可以喚醒等到隊列中的第一個等待同一共享資源的線程,並使該線程退出等待隊列,進入可運行狀態。
– notifyAll():喚醒所有等待的線程,可以使所有的正在等待的隊列中同一共享資源的線程從等待隊列狀態退出,進入可運行狀態。
以上三個方法均屬於Object類,每個對象都有這幾個功能,不屬於Thread類

15.線程的通信

1.通信的方法
1)wait():令當前線程掛起並放棄cpu,使別的線程可以訪問並修改共享資源。(等待)
2)notify():喚醒正在排隊等候優先級最高的同步資源的線程。(單個線程)
3)notifyAll():喚醒正在排隊等待資源的所有線程。
2.注意問題
1)下面三個通信方法都不屬於Thread類,屬於Object類,每個對象都擁有以上三個方法,因爲每個對象都有鎖,鎖是每個對象的基礎。
2)當需要調用以下方法的時候,一定要對共享資源進行加鎖,不加鎖會引發異常。
3)當想要調用wait()方法進行線程等待的時候,必須要取得這個鎖對象的控制權(對象監控器),一般是放到synchronized(obj)代碼塊中
4)調用wait相當於釋放了鎖,否則其他線程無法獲得鎖。

16.生產者消費者問題實現
package com.hpe.exercise1;
/**
 * 生產者和消費者模式
 * 1.生產者和消費者共享同一數據(倉庫),並且生產者和消費者之間相互依賴
 * 2.如何解決同步問題?
 *  -- 傳統的思路:可以使用循環檢測的方式,比較耗費cpu資源
 *  -- 線程通信的方式:
 *  	wait():可以使用此方法使線程釋放共享資源的鎖,然後從運行狀態退出,進入等待隊列,直到喚醒
 *  	notify():可以喚醒等待隊列中共享資源的進程,並使該線程退出等待隊列,進入可運行狀態。
 *  	notifyAll()
 */
class Clerk{
	int product = 20;// 消費
	// 生產產品的方法
	public synchronized void addProduct() {
		if(product >= 20) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else {
			// 繼續生產
			product++;
			System.out.println(Thread.currentThread().getName()+"生產了第"+product+"個產品");
			notifyAll();
		}
	}
	// 消費產品的方法
	public synchronized void consumeProduct() {
		if(product <= 0) {
			try {
				// 停止消費
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}else {
			// 繼續消費
			product --;
			System.out.println(Thread.currentThread().getName()+"消費了第"+product+"個產品");
			notifyAll();// 喚醒所有線程
		}
	}
}
//生產者
class Producer implements Runnable{
	Clerk clerk;
	public Producer(Clerk clerk) {
		this.clerk = clerk;
	}
	@Override
	public void run() {
		// 生產產品
		System.out.println("生產者開始生產產品...");
		while(true) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			// 調用生產產品的方法
			clerk.addProduct();
		}
	}
	
}
//消費者
class Consumer implements Runnable{
	Clerk clerk;
	public Consumer(Clerk clerk) {
		this.clerk = clerk;
	}
	@Override
	public void run() {
		System.out.println("消費者開始消費產品...");
		while(true) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			// 調用消費產品的方法
			clerk.consumeProduct();
		}
	}
	
}
public class TestProduce {
	public static void main(String[] args) {
		Clerk clerk = new Clerk();
		// 創建生產者對象
		Producer p1 = new Producer(clerk);
		// 創建消費者對象
		Consumer c1 = new Consumer(clerk);
		// 創建生產者的線程
		Thread t1 = new Thread(p1);
		// 創建消費者的線程
		Thread t2 = new Thread(c1);
		Thread t3 = new Thread(c1);
		
		
		t1.setName("生產者1:");
		t2.setName("消費者1:");
		t3.setName("消費者2:");
		
		t1.start();
		t2.start();
		t3.start();
	}
}

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