Java 併發 (多線程) 講解


多線程的概念是相對於順序編程 而言的,在順序編程裏,程序只能按照一條線進行執行,而多線程可以打破這一限制,實現併發 效果。


多線程的基本實現方式


繼承Thread


通過繼承Thread類可以實現新的線程,這樣會很簡便,但一般來說,是不被建議這樣使用的。

它最大的缺陷是,一旦繼承了Thread類就無法繼承別的類,對設計造成一定的影響。


以下的demo中,我們通過繼承Thread類來實現多線程。

共開啓5個線程,線程名字分別初始化爲15的數字。每個線程開始執行後,均是每隔一秒輸出一次當前狀態。


class InheritThread extends Thread {
	
	private int waitSeconds = 5;
	
	private static int threadCount = 0;
	
	public InheritThread() {
		super(Integer.toString(threadCount++));
	}
	
	public void run() {
		while (waitSeconds > 0) {
			System.out.print(this);
			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			waitSeconds--;
		}
	}
	
	//override toString method
	public String toString() {
		String name = getName();
		String info = "InheritThread:" +  name + ", current waitSeconds = " + waitSeconds + "\n";
		return info;
	}
}


public class TestClass {

	public static void main(String[] args) {

			Thread thread;
			for (int i = 0; i < 5; i++) {
				thread = new InheritThread();
				thread.start();
			}
	}

}

輸出結果:(對於多線程問題,不同機器和平臺上,同樣的代碼也可能產生不同的結果)

InheritThread:1, current waitSeconds = 5
InheritThread:2, current waitSeconds = 5
InheritThread:3, current waitSeconds = 5
InheritThread:4, current waitSeconds = 5
InheritThread:5, current waitSeconds = 5
InheritThread:1, current waitSeconds = 4
InheritThread:2, current waitSeconds = 4
InheritThread:3, current waitSeconds = 4
InheritThread:4, current waitSeconds = 4
InheritThread:5, current waitSeconds = 4
InheritThread:1, current waitSeconds = 3
InheritThread:2, current waitSeconds = 3
InheritThread:3, current waitSeconds = 3
InheritThread:4, current waitSeconds = 3
InheritThread:5, current waitSeconds = 3
InheritThread:1, current waitSeconds = 2
InheritThread:3, current waitSeconds = 2
InheritThread:2, current waitSeconds = 2
InheritThread:4, current waitSeconds = 2
InheritThread:5, current waitSeconds = 2
InheritThread:1, current waitSeconds = 1
InheritThread:2, current waitSeconds = 1
InheritThread:3, current waitSeconds = 1
InheritThread:4, current waitSeconds = 1
InheritThread:5, current waitSeconds = 1


實現Runnable接口


Runnable是JDK裏的一個接口,我們可以把它理解爲一個 "任務“, 即是我們要用它實現的線程執行的任務。

Thread類本身就是實現了Runnable接口的,所以我們纔可以直接繼承Thread類實現線程。


同樣,我們只需實現Runnable接口(複寫它的 run 方法), 就可以用它來實現線程。


以下的例子所做的操作和上個例子基本是一樣的:

class ImpRunnable implements Runnable {

	private int waitSeconds = 5;
	
	private static int threadCount = 0;
	
	private final int myThreadCount = threadCount;
	
	public ImpRunnable() {
		threadCount++;
	}
	
	public void run() {
		while (waitSeconds > 0) {
			System.out.print(this);
			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			waitSeconds--;
		}
	}
	
	//override toString method
	public String toString() {
		String name = "ImplRunnabeThread:" + myThreadCount;
		String info = name + ", current waitSeconds = " + waitSeconds + "\n";
		return info;
	}
	
}

public class TestClass {

	public static void main(String[] args) {

			Thread thread;
			for (int i = 0; i < 5; i++) {
				
				thread = new Thread(new ImpRunnable());
				thread.start();
			}
	}

}

輸出結果:

ImplRunnabeThread:0, current waitSeconds = 5
ImplRunnabeThread:1, current waitSeconds = 5
ImplRunnabeThread:2, current waitSeconds = 5
ImplRunnabeThread:3, current waitSeconds = 5
ImplRunnabeThread:4, current waitSeconds = 5
ImplRunnabeThread:0, current waitSeconds = 4
ImplRunnabeThread:1, current waitSeconds = 4
ImplRunnabeThread:2, current waitSeconds = 4
ImplRunnabeThread:3, current waitSeconds = 4
ImplRunnabeThread:4, current waitSeconds = 4
ImplRunnabeThread:0, current waitSeconds = 3
ImplRunnabeThread:1, current waitSeconds = 3
ImplRunnabeThread:2, current waitSeconds = 3
ImplRunnabeThread:3, current waitSeconds = 3
ImplRunnabeThread:4, current waitSeconds = 3
ImplRunnabeThread:0, current waitSeconds = 2
ImplRunnabeThread:1, current waitSeconds = 2
ImplRunnabeThread:2, current waitSeconds = 2
ImplRunnabeThread:3, current waitSeconds = 2
ImplRunnabeThread:4, current waitSeconds = 2
ImplRunnabeThread:0, current waitSeconds = 1
ImplRunnabeThread:1, current waitSeconds = 1
ImplRunnabeThread:2, current waitSeconds = 1
ImplRunnabeThread:3, current waitSeconds = 1
ImplRunnabeThread:4, current waitSeconds = 1


幾種常用的線程操作


休眠


可以通過  Thread.sleep( millseconds )方法使線程終止執行給定的時間。

(以上兩個demo中均使用了該方法)


注意使用該方法時需要捕獲 InterruptedException.


讓步


系統在實現多線程時,其實是對cpu的使用時間進行了切分,通過策略分別分配給各個線程cpu的使用機會。


如果我們在實現線程時,某些時間段不需要使用cpu,那麼我們可以通過 Thread.yield() 方法通知線程調度器: 我現在暫時不需要cpu了,讓別的線程使用吧。


但是要注意:這僅僅是一個暗示或者提示,沒有任何機制能夠保證系統會分配給其他線程cpu使用。所以不要完全依賴於 yield 來調度多線程的執行。



設置優先級


初始化一個線程後,它會按照默認的優先級運行。但我們也可以認爲設置線程的優先級。

cpu調度器會傾向於讓優先級高的線程先執行,但並不是說低優先級的線程不被執行,只是執行的頻率會相對低一些。

可以通過 getPriority()方法獲取當前線程的優先級,通過setPriority()方法設置優先級。



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