執行緒基礎:執行緒(1)——作業系統和執行緒原理
1、概述
我在寫“系統間通訊技術專欄”的時候,收到很多讀者的反饋。其中有一部分讀者希望我抽空寫一寫自己關於對JAVA執行緒的使用經驗和總結。巧的是,這個月我所在的技術團隊也有很多同事跟我討論關於JAVA中執行緒的操作。正好本月我工作也不是很忙,除了繼續推進我的重點專欄“系統間通訊技術”外,可以更多的空餘時間跟各位讀者分享自己對JAVA執行緒技術的理解和使用經驗。
本人不才,應讀者要求新開專欄,與各位讀者分享自己對JAVA執行緒技術的理解和使用經驗。這個專欄將分成兩個部分:執行緒基礎知識和鎖知識。專欄的難度應該是我所開專欄中難度最低的一個,著重於執行緒基礎知識的講解,更適合JAVA初學者閱讀,目的是希望能夠幫助大家提高codeing水平和程式質量。如果您是經驗老道的高手也歡迎和本人討論相關問題,對本人文章的論點進行勘誤,您的支援是我寫作的關鍵動力。當然本人的更多精力還是放在繼續完成“
2、作業系統和執行緒原理
執行緒是一個作業系統級別的概念。JAVA語言(包括其他程式語言)本身不建立執行緒;而是呼叫作業系統層提供的介面建立、控制、銷燬執行緒例項。
首先要說明的是,根據作業系統的不同(Windows/Unix/Linux/其他),他們所支援的執行緒底層實現和操作效果也是不盡相同的。不過一個作業系統支援的執行緒至少會有四種狀態:就緒、執行、阻塞和終結。執行緒在四種狀態下進行切換,都是要消耗不少的CPU計算能力的。
並且根據作業系統使用執行緒的程序的不一樣,執行緒還分為使用者執行緒和作業系統執行緒。作業系統執行緒(核心執行緒),是指作業系統核心為了完成硬體介面層操作,由作業系統核心建立的執行緒:例如I/O操作的核心執行緒,這些執行緒應用程式是不能干預的;使用者執行緒,是指使用者安裝/管理的應用程式,為執行某一種操作,而由這個應用程式建立的執行緒。後文我們討論的JAVA執行緒,都是使用者級執行緒
執行緒在建立時,作業系統不會為這個執行緒分配獨立的資源(除了必要的資料支撐)。一個應用程式(程序)下的所有執行緒,都是共享這個應用程式(程序)中的資源,例如這個應用程式的CPU資源、I/O資源、記憶體資源。
現在基本上主流作業系統都支援多執行緒實現。即一個應用程式中(一個程序中),可以建立多個執行緒。一個應用程式下,各個執行緒間都可以進行通訊、可以進行狀態互操作。且一個程序中,至少有一個執行緒存在。
3、JAVA中最簡單的執行緒示例
JAVA中提供了豐富的作業系統介面實現,幫助我們進行執行緒操作。這些實現分佈在java的java.lang基礎包、java.io基礎包和java.util.concurrent工具包當中;這個專欄所涉及到的程式碼示例也會從易到難向大家進行演示。我們先來看看JAVA中最基本的執行緒操作實現(高手請繞行)。
3-1、Thread父類
java.lang.Thread類是JAVA中用於實現執行緒操作的最基本的類之一。您可以建立一個整合Thread類的子類來定義您自己的執行緒實現:
package test.thread.base;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.BasicConfigurator;
public class MyDefindThread extends Thread {
static {
BasicConfigurator.configure();
}
/**
* 日誌。一定要使用Log4j才行。否則你就用System.out吧
*/
private static final Log LOGGER= LogFactory.getLog(MyDefindThread.class);
/* (non-Javadoc)
* @see java.lang.Thread#run()
*/
@Override
public void run() {
Long threadId = this.getId();
MyDefindThread.LOGGER.info("執行緒(" + threadId + ")做了一些事情,然後結束了。");
}
public static void main(String[] args) throws Exception {
new MyDefindThread().start();
}
}
3-2、Runable介面
除了可以繼承java.lang.Thread類來定義自己的執行緒外,您還可以實現java.lang.Runnable介面來定義一個執行緒(一般情況,我們優先使用這種方式):
package test.thread.base;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.BasicConfigurator;
public class MyDefindRunnable implements Runnable {
static {
BasicConfigurator.configure();
}
/**
* 日誌。一定要使用Log4j才行。否則你就用System.out吧
*/
private static final Log LOGGER= LogFactory.getLog(MyDefindThread.class);
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
// 獲取當前執行緒的ID
long threadId = Thread.currentThread().getId();
MyDefindRunnable.LOGGER.info("執行緒(" + threadId + ")做了一些事情,然後結束了。");
}
public static void main(String[] args) throws Exception {
new Thread(new MyDefindRunnable()).start();
}
}
以上的兩段程式碼都沒有太多可講解的。您可以在除錯環境下觀察到JAVA應用程式是如何執行執行緒的:
4、下文介紹
下一篇文章中,我們將繼續介紹Java所支援的執行緒間基本互操作,包括:阻塞、喚醒、終止等操作;然後介紹Java原生執行緒池的工作原理和基本操作。