線程基礎:線程(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類的子類來定義您自己的線程實現:

 1 package test.thread.base;
 2 
 3 import org.apache.commons.logging.Log;
 4 import org.apache.commons.logging.LogFactory;
 5 import org.apache.log4j.BasicConfigurator;
 6 
 7 public class MyDefindThread extends Thread {
 8 
 9     static {
10         BasicConfigurator.configure();
11     }
12 
13     /**
14      * 日志。一定要使用Log4j才行。否則你就用System.out吧
15      */
16     private static final Log LOGGER= LogFactory.getLog(MyDefindThread.class);
17 
18     /* (non-Javadoc)
19      * @see java.lang.Thread#run()
20      */
21     @Override
22     public void run() {
23         Long threadId =  this.getId();
24         MyDefindThread.LOGGER.info("線程(" + threadId + ")做了一些事情,然后結束了。");
25     }
26 
27     public static void main(String[] args) throws Exception {
28         new MyDefindThread().start();
29     }
30 }

 

3-2、Runable接口

除了可以繼承java.lang.Thread類來定義自己的線程外,您還可以實現java.lang.Runnable接口來定義一個線程(一般情況,我們優先使用這種方式):

 1 package test.thread.base;
 2 
 3 import org.apache.commons.logging.Log;
 4 import org.apache.commons.logging.LogFactory;
 5 import org.apache.log4j.BasicConfigurator;
 6 
 7 public class MyDefindRunnable implements Runnable {
 8 
 9     static {
10         BasicConfigurator.configure();
11     }
12 
13     /**
14      * 日志。一定要使用Log4j才行。否則你就用System.out吧
15      */
16     private static final Log LOGGER= LogFactory.getLog(MyDefindThread.class);
17 
18     /* (non-Javadoc)
19      * @see java.lang.Runnable#run()
20      */
21     @Override
22     public void run() {
23         // 獲取當前線程的ID
24         long threadId = Thread.currentThread().getId();
25         MyDefindRunnable.LOGGER.info("線程(" + threadId + ")做了一些事情,然后結束了。");
26     }
27 
28     public static void main(String[] args) throws Exception {
29         new Thread(new MyDefindRunnable()).start();
30     }
31 }

以上的兩段代碼都沒有太多可講解的。您可以在調試環境下觀察到JAVA應用程序是如何運行線程的:

這里寫圖片描述

4、下文介紹

下一篇文章中,我們將繼續介紹Java所支持的線程間基本互操作,包括:阻塞、喚醒、終止等操作;然后介紹Java原生線程池的工作原理和基本操作。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM