## Java編程那些事兒94——多線程實現方式1
陳躍峰
出自:[http://blog.csdn.net/mailbomb](http://blog.csdn.net/mailbomb)
### 12.2 多線程實現方式
線程的概念雖然比較復雜,但是在Java語言中實現線程卻比較簡單,只需要按照Java語言中對于線程的規定進行編程即可。
在實現線程編程時,首先需要讓一個類具備多線程的能力,繼承Thread類或實現Runnable接口的類具備多線程的能力,然后創建線程對象,調用對應的啟動線程方法開始執行即可實現多線程編程。
在一個程序中可以實現多個線程,多線程編程指在同一個程序中啟動了兩個或兩個以上的編程形式。當啟動的線程數量比較多時,對于系統資源的要求比較多,所以程序支持的最大線程數量和計算機的硬件配置相關。
在實際實現線程時,Java語言提供了三種實現方式:
1、? 繼承Thread類
2、? 實現Runnable接口
3、? 使用Timer和TimerTask組合
下面依次介紹每種實現方式的代碼編寫,以及各種實現之間的區別比較。
### 12.2.1 繼承Thread類
如果一個類繼承了Thread類,則該類就具備了多線程的能力,則該類則可以以多線程的方式進行執行。
但是由于Java語言中類的繼承是單重繼承,所以該方式受到比較大的限制。
下面以一個簡單的示例介紹該種多線程實現方式的使用以及啟動線程的方式。示例代碼如下所示:
~~~
/**
?* 以繼承Thread的方式實現線程
?*/
public class FirstThread extends Thread{
???????? public static void main(String[] args) {
?????????????????? //初始化線程
?????????????????? FirstThread ft = new FirstThread();
?????????????????? //啟動線程
?????????????????? ft.start();
??????????????????
?????????????????? try{
??????????????????????????? for(int i = 0;i < 10;i++){
???????????????????????????????????? //延時1秒
???????????????????????????????????? Thread.sleep(1000);
???????????????????????????????????? System.out.println("main:" + i);
??????????????????????????? }
?????????????????? }catch(Exception e){}
???????? }
?
???????? public void run(){
?????????????????? try{
??????????????????????????? for(int i = 0;i < 10;i++){
???????????????????????????????????? //延時1秒
???????????????????????????????????? Thread.sleep(1000);
???????????????????????????????????? System.out.println("run:" + i);
??????????????????????????? }
?????????????????? }catch(Exception e){}
???????? }
}
~~~
在該程序中,通過使FirstThread繼承Thread類,則FirstThread類具備了多線程的能力,按照Java語言線程編程的規定,線程的代碼必須書寫在run方法內部或者在run方法內部進行調用,在示例的代碼中的run方法實現的代碼作用是每隔1秒輸出一行文字。換句話說,run方法內部的代碼就是自定義線程代碼,或者說,自定義線程的代碼必須書寫在run方法的內部。
在執行FirstThread類時,和前面的執行流程一樣。當執行FirstThread類時,Java虛擬機將開啟一個系統線程來執行該類的main方法,main方法的內部代碼按照順序結構進行執行,首先執行線程對象的初始化,然后執行調用start方法。該行代碼的作用是啟動線程,在執行start方法時,不阻塞程序的執行,start方法的調用立刻返回,Java虛擬機以自己的方式啟動多線程,開始執行該線程對象的run方法。同時系統線程的執行流程繼續按照順序執行main方法后續的代碼,執行main方法內部的輸出。
這樣,在FirstThread執行時,就有了兩個同時執行的流程:main流程和自定義run方法流程,換句專業點的話來說,就是該程序在執行時有兩個線程:系統線程和自定義線程。這個同時執行可以從該程序的執行結果中獲得更加直接的證明。
該程序的執行結果為:
run:0
main:0
main:1
run:1
main:2
run:2
main:3
run:3
main:4
run:4
main:5
run:5
main:6
run:6
main:7
run:7
main:8
run:8
main:9
run:9
從執行結果可以看到兩個線程在同時執行,這將使我們進入多線程編程的時代,進入并發編程的領域,體會神奇的多線程編程的魔力。
由于兩個線程中的延遲時間——1秒,是比較長的,所以看到的結果是線程規律執行的,其實真正的線程執行順序是不能直接保證的,系統在執行多線程程序時只保證線程是交替執行的,至于那個線程先執行那個線程后執行,則無法獲得保證,需要書寫專門的代碼才可以保證執行的順序。
其實,上面的代碼可以簡化,簡化以后的代碼為:
~~~
/**
?* 以繼承Thread的方式實現線程2
?* 使用方法簡化代碼
?*/
public class SecondThread extends Thread{
???????? public static void main(String[] args) {
?????????????????? //初始化線程
?????????????????? SecondThread ft = new SecondThread();
?????????????????? //啟動線程
?????????????????? ft.start();
??????????????????
?????????????????? print("main:");
???????? }
?
???????? public void run(){
?????????????????? print("run:");
???????? }
????????
???????? private static void print(String s){
?????????????????? try{
??????????????????????????? for(int i = 0;i < 10;i++){
???????????????????????????????????? //延時1秒
???????????????????????????????????? Thread.sleep(1000);
???????????????????????????????????? System.out.println(s + i);
??????????????????????????? }
?????????????????? }catch(Exception e){}
???????? }
}
~~~
在該示例代碼中,將重復的代碼組織稱print方法,分別在main方法和run方法內部調用該方法。需要特別強調的是,在run方法內部調用的方法,也會以多線程多線程的方式被系統執行,這樣更加方便代碼的組織。
其實在實際實現時,還可以把線程以單獨類的形式出現,這樣實現的代碼如下所示:
~~~
/**
?* 測試類
?*/
public class Test {
???????? public static void main(String[] args) {
?????????????????? //初始化線程
?????????????????? ThirdThread ft = new ThirdThread();
?????????????????? //啟動線程
?????????????????? ft.start();
??????????????????
?????????????????? try{
??????????????????????????? for(int i = 0;i < 10;i++){
???????????????????????????????????? //延時1秒
???????????????????????????????????? Thread.sleep(1000);
???????????????????????????????????? System.out.println("main:" + i);
??????????????????????????? }
?????????????????? }catch(Exception e){}
???????? }
}
???????? /**
?* 以繼承Thread類的方式實現多線程3
?* 以單獨類的實現組織代碼
?*/
public class ThirdThread extends Thread {
???????? public void run(){
?????????????????? try{
??????????????????????????? for(int i = 0;i < 10;i++){
???????????????????????????????????? //延時1秒
???????????????????????????????????? Thread.sleep(1000);
???????????????????????????????????? System.out.println("run:" + i);
??????????????????????????? }
?????????????????? }catch(Exception e){}
???????? }
}
~~~
在該示例代碼中,ThirdThread類是一個單獨的線程類,在該類的run方法內部實現線程的邏輯,使用該種結構符合面向對象組織代碼的方式。需要啟動該線程時,和前面啟動的方式一致。
一個類具備了多線程的能力以后,可以在程序中需要的位置進行啟動,而不僅僅是在main方法內部啟動。
對于同一個線程類,也可以啟動多個相同的線程,例如以ThirdThread類為例,啟動兩次的代碼為:
~~~
?????????????????? ThirdThread t1 = new ThirdThread();
?????????????????? t1.start();
?????????????????? ThirdThread t2 = new ThirdThread();
?????????????????? t2.start();
~~~
而下面的代碼是錯誤的
~~~
?????????????????? ThirdThread t1 = new ThirdThread();
?????????????????? t1.start();
?????????????????? t1.start(); //同一個線程不能啟動兩次
~~~
當自定義線程中的run方法執行完成以后,則自定義線程將自然死亡。而對于系統線程來說,只有當main方法執行結束,而且啟動的其它線程都結束以后,才會結束。當系統線程執行結束以后,則程序的執行才真正結束。
總之,繼承Thread類可以使該類具備多線程的能力,需要啟動該線程時,只需要創建該類的對象,然后調用該對象中的start方法,則系統將自動以多線程的發那個是執行該對象中的run方法了。
雖然該種方式受到Java語法中類的單重繼承的限制,但是在實際的項目中還是獲得了比較廣泛的使用,是一種最基本的實現線程的方式。
- 前言
- (1)序言
- (2)程序設計是什么?
- (3)你適合學習程序設計嗎?
- (4)如何學好程序設計?
- (5)程序設計介紹小結
- (6)計算機軟件基本概念
- (7)進制的概念
- (8)計算機內部的數據表達
- (9)網絡編程基礎
- (10)Java語言簡介
- (11)JDK的獲得、安裝和配置
- (12)第一個HelloWorld程序
- (13)Eclipse基本使用
- (14)Eclipse基礎使用進階
- (15)如何學好Java語法
- (16)代碼框架、關鍵字和標識符
- (17)基本數據類型
- (18)變量和常量
- (19)數據類型轉換
- (20)空白、語句結束和注釋
- (21)算術運算符
- (22)比較運算符
- (23)邏輯運算符
- (24)賦值運算符
- (25)位運算符
- (26)移位運算符
- (27)其它運算符
- (28)運算符優先級
- (29)表達式
- (30)流程控制基礎
- (31)if語句語法(1)
- (32)if語句語法(2)
- (33)if語句語法(3)
- (34)switch語句語法
- (35)while語句語法
- (36)do-while語句語法
- (37)for語句語法
- (38)break和continue語句
- (39)流程控制綜合示例1
- (40)流程控制綜合示例2
- (41)流程控制綜合示例3
- (42)流程控制綜合練習
- (43)數組概述
- (44)數組基礎語法
- (45)數組使用示例1
- (46)數組使用示例2
- (47)數組使用示例3
- (48)多維數組基礎
- (49)多維數組使用示例1
- (50)多維數組使用示例2
- (51)多維數組練習
- (52)方法聲明
- (53)方法聲明示例
- (54)方法調用
- (55)方法重載和參數傳遞
- (56)方法練習
- (57)面向對象基礎
- (58)類(一)
- (59)類(二)
- (60)對象
- (61)面向對象設計方法和面向對象特性(一)
- (62)繼承(二)
- (63)多態性
- (64)訪問控制符、修飾符和其它關鍵字
- (65)static修飾符
- (66)final修飾符
- (67)this和super
- (68)抽象類和接口(一)
- (69)抽象類和接口(二)
- (70)抽象類和接口(三)
- (71)內部類簡介
- (72)包的概念
- (73)JDK文檔使用
- (74)java.lang包介紹1
- (75)String類使用
- (76)StringBuffer類和System類
- (77)包裝類
- (78)時間和日期處理
- (79)Random隨機處理
- (80)集合框架簡述
- (81)異常處理概述
- (82)異常處理語法1
- (83)異常處理語法2
- (84)IO簡介
- (85)IO類體系
- (86)文件操作之File類使用
- (87)文件操作之讀取文件
- (88)文件操作之寫文件
- (89)讀取控制臺輸入
- (90)裝飾流使用1
- (91)裝飾流使用2
- (92)IO使用注意問題
- (93)多線程基礎
- (94)多線程實現方式1
- (95)多線程實現方式2
- (96)多線程使用示例1
- (97)多線程使用示例2
- (98)多線程問題及處理1
- (99)多線程問題及處理2
- (100)多線程問題及處理3
- (101)網絡編程概述
- (102)網絡編程技術1
- (103)網絡編程技術2
- (104)網絡編程技術3
- (105)網絡編程技術4
- (106)網絡編程技術5
- (107)網絡協議概念
- (108)網絡編程示例1
- (109)網絡編程示例2
- (110)網絡編程小結