金艷 夏仕安 張佑龍 方素貞 朱生水
摘要:MSDP是廣東省地震局開發(fā)的地震交互分析處理軟件,在我們的日常工作中發(fā)揮了重要作用。文章就MSDP的多線程技術(shù)進(jìn)行了簡要分析,以便加深對MSDP的基本原理的了解和掌握。
關(guān)鍵詞:MSDP;多線程;JAVA;線程優(yōu)先級
中圖分類號(hào):TP274 文獻(xiàn)標(biāo)識(shí)碼:A 文章編號(hào):1009-2374(2013)05-0020-03
1 概述
MSDP是地震系統(tǒng)常用的地震交互分析處理軟件,MSDP采用了大量的Java技術(shù),Java多線程就是其中之一。
在Java語言產(chǎn)生前,傳統(tǒng)的程序設(shè)計(jì)語言的程序同一時(shí)刻只能單任務(wù)操作,效率非常低,例如程序往往在接收數(shù)據(jù)輸入時(shí)發(fā)生阻塞,只有等到程序獲得數(shù)據(jù)后才能繼續(xù)運(yùn)行。隨著Internet的迅猛發(fā)展,這種狀況越來越不能讓人們?nèi)淌埽喝绻W(wǎng)絡(luò)接收數(shù)據(jù)阻塞,后臺(tái)程序就處于等待狀態(tài)而不繼續(xù)任何操作,而這種阻塞是經(jīng)常會(huì)碰到的,此時(shí)CPU資源被白白地閑置起來。如果在后臺(tái)程序中能夠同時(shí)處理多個(gè)任務(wù),該多好??!應(yīng)Internet技術(shù)而生的Java語言解決了這個(gè)問題,多線程程序是Java語言的一個(gè)很重要的特點(diǎn)。在一個(gè)Java程序中,我們可以同時(shí)并行運(yùn)行多個(gè)相對獨(dú)立的線程,例如,我們?nèi)绻麆?chuàng)建一個(gè)線程來進(jìn)行數(shù)據(jù)輸入輸出,而創(chuàng)建另一個(gè)線程在后臺(tái)進(jìn)行其他的數(shù)據(jù)處理,如果輸入輸出線程在接收數(shù)據(jù)時(shí)阻塞,而處理數(shù)據(jù)的線程仍然在運(yùn)行。多線程程序設(shè)計(jì)大大提高了程序的執(zhí)行效率和處理能力。
2 多線程的概念
每個(gè)正在系統(tǒng)上運(yùn)行的程序都是一個(gè)進(jìn)程。每個(gè)進(jìn)程包含一到多個(gè)線程。進(jìn)程也可能是整個(gè)程序或者是部分程序的動(dòng)態(tài)執(zhí)行。線程是一組指令的集合或者是程序的特殊段,它可以在程序里獨(dú)立執(zhí)行,也可以把它理解為代碼運(yùn)行的上下文。所以線程基本上是輕量級的進(jìn)程,它負(fù)責(zé)在單個(gè)程序里執(zhí)行多任務(wù)。通常由操作系統(tǒng)負(fù)責(zé)多個(gè)線程的調(diào)度和執(zhí)行。
線程是程序中一個(gè)單一的順序控制流程。在單個(gè)程序中同時(shí)運(yùn)行多個(gè)線程完成不同的工作,稱為多線程。線程和進(jìn)程的區(qū)別在于,子進(jìn)程和父進(jìn)程有不同的代碼和數(shù)據(jù)空間,而多個(gè)線程則共享數(shù)據(jù)空間,每個(gè)線程有自己的執(zhí)行堆棧和程序計(jì)數(shù)器為其執(zhí)行上下文,多線程主要是為了節(jié)約CPU時(shí)間。
使用多線程的優(yōu)點(diǎn):使用線程可以把占據(jù)長時(shí)間的程序中的任務(wù)放到后臺(tái)去處理;用戶界面可以更加吸引人,這樣比如用戶點(diǎn)擊了一個(gè)按鈕去觸發(fā)某些事件的處理,可以彈出一個(gè)進(jìn)度條來顯示處理的進(jìn)度;程序的運(yùn)行速度可能加快;在一些等待的任務(wù)實(shí)現(xiàn)上如用戶輸入、文件讀寫和網(wǎng)絡(luò)收發(fā)數(shù)據(jù)等,線程就比較有用了,在這種情況下可以釋放一些珍貴的資源如內(nèi)存占用等。
3 多線程的創(chuàng)建與使用
3.1 多線程的創(chuàng)建
我們知道Java是面向?qū)ο蟮某绦蛘Z言,用Java進(jìn)行程序設(shè)計(jì)就是設(shè)計(jì)和使用類,Java為我們提供了線程類Thread來創(chuàng)建線程,創(chuàng)建線程與創(chuàng)建普通的類的對象的操作是一樣的,而線程就是Thread類或其子類的實(shí)例對象。下面是創(chuàng)建啟動(dòng)一個(gè)線程的語句:
Thread thread1=new Thread();//聲明一個(gè)對象實(shí)例,即創(chuàng)建一個(gè)線程;
Thread1.run();//用Thread類中的run()方法啟動(dòng)線程;
從這個(gè)例子中,我們可以通過Thread()構(gòu)造方法創(chuàng)建一個(gè)線程,并啟動(dòng)該線程。事實(shí)上,啟動(dòng)線程,也就是啟動(dòng)線程的run()方法,而Thread類中的run()方法沒有任何操作語句,所以這個(gè)線程沒有任何操作。要使線程實(shí)現(xiàn)預(yù)定功能,必須定義自己的run()方法。Java中通常有兩種方式定義run()方法:
3.1.1 通過定義一個(gè)Thread類的子類,在該子類中重寫run()方法。Thread子類的實(shí)例對象就是一個(gè)線程,顯然,該線程有我們自己設(shè)計(jì)的線程體run()方法,啟動(dòng)線程就啟動(dòng)了子類中重寫的run()方法。
3.1.2 因?yàn)橛袝r(shí)要作為線程運(yùn)行的類可能已經(jīng)是某個(gè)類層次的一部分,所以就不能再按這種機(jī)制創(chuàng)建線程。雖然在同一個(gè)類中可以實(shí)現(xiàn)任意數(shù)量的接口,但Java編程語言只允許一個(gè)類有一個(gè)父類。同時(shí),某些程序員避免從Thread類導(dǎo)出,因?yàn)樗鼜?qiáng)加了類層次。對于這種情況,就要Runnable接口。通過Runnable接口,在該接口中定義run()方法的接口。所謂接口跟類非常類似,主要用來實(shí)現(xiàn)特殊功能,如復(fù)雜關(guān)系的多重繼承功能。在此,我們定義一個(gè)實(shí)現(xiàn)Runnable()接口的類,在該類中定義自己的run()方法,然后以該類的實(shí)例對象為參數(shù)調(diào)用Thread類的構(gòu)造方法來創(chuàng)建一個(gè)
線程。
在具體應(yīng)用中,采用哪種方法來構(gòu)造線程體要視情況而定。通常,當(dāng)一個(gè)線程已繼承了另一個(gè)類時(shí),就應(yīng)該用第二種方法來構(gòu)造,即實(shí)現(xiàn)Runnable接口。正如它的名字一樣,Runnable的實(shí)例是可運(yùn)行的,但它自己并不能直接運(yùn)行,它需要被Thread對象來包裝才能運(yùn)行。
使用Runnable接口來實(shí)現(xiàn)多線程使得我們能夠在一個(gè)類中包容所有的代碼,有利于封裝,它的缺點(diǎn)在于,我們只能使用一套代碼,若想創(chuàng)建多個(gè)線程并使各個(gè)線程執(zhí)行不同的代碼,則仍須額外創(chuàng)建類,如果這樣的話,在大多數(shù)情況下也許還不如直接用多個(gè)類分別繼承Thread來得緊湊。
3.2 線程的優(yōu)先級
對于多線程程序,每個(gè)線程的重要程度不盡相同,如多個(gè)線程在等待獲得CPU時(shí)間時(shí),往往我們需要優(yōu)先級高的線程優(yōu)先搶占到CPU時(shí)間得以執(zhí)行;又如多個(gè)線程交替執(zhí)行時(shí),優(yōu)先級決定了級別高的線程得到CPU的次數(shù)多一些且時(shí)間多長一些。這樣,高優(yōu)先級的線程處理的任務(wù)效率就高一些。
Java中線程的優(yōu)先級從低到高以整數(shù)1-10表示,共分為10級,設(shè)置優(yōu)先級是通過調(diào)用線程對象的setPriority()方法,如上例中,設(shè)置優(yōu)先級的語句為:
thread1 threadone=new thread1();//用Thread類的子類創(chuàng)建線程;
Thread threadtwo=new Thread(new thread2());//用Runnable接口類的對象創(chuàng)建線程;
threadone.setPriority(6);//設(shè)置threadone的優(yōu)先級6;
threadtwo.setPriority(3);//設(shè)置threadtwo的優(yōu)先級3;
threadone.start();threadtwo.start();//strat()方法啟動(dòng)線程;
這樣,線程threadone將會(huì)優(yōu)先于線程threadtwo執(zhí)行,并將占有更多的CPU時(shí)間。該例中,優(yōu)先級設(shè)置放在線程啟動(dòng)前,也可以在啟動(dòng)后進(jìn)行設(shè)置,以滿足不同的優(yōu)先級需求。
3.3 線程的狀態(tài)
線程也是有狀態(tài)和生命周期的,每個(gè)Java程序都會(huì)有一個(gè)缺省的主線程,對于應(yīng)用程序applcation來說main方法就是一個(gè)主線程。Java語言使用的是Thread類及其子類的對象來表示線程的。創(chuàng)建一個(gè)新的線程的生命周期如下狀態(tài):
3.3.1 新建:當(dāng)一個(gè)Thread類或者其子類的對象被聲明并創(chuàng)建時(shí),新的線程對象處于新建狀態(tài),此時(shí)它已經(jīng)有了相應(yīng)的內(nèi)存空間和其他資源。
3.3.2 就緒:處于新建狀態(tài)的線程被啟動(dòng)后,將進(jìn)入線程隊(duì)列排隊(duì)等待CUP服務(wù),這個(gè)時(shí)候具備了運(yùn)行的條件,一旦輪到CPU的時(shí)候,就可以脫離創(chuàng)建它的主線程獨(dú)立開始自己的生命周期。
3.3.3 運(yùn)行:就緒的線程被調(diào)度并獲得CUP的處理進(jìn)入了運(yùn)行狀態(tài),每一個(gè)Thread類及其子類的對象都有一個(gè)重要的run()方法,當(dāng)線程對象被調(diào)度執(zhí)行的時(shí)候,它將自動(dòng)調(diào)用本對象的run()方法,從第一句代碼開始執(zhí)行。所以說對線程的操作應(yīng)該寫到run()方法中。
3.3.4 阻塞:一個(gè)正在執(zhí)行的線程如果在某種情況下不能執(zhí)行了,進(jìn)入阻塞狀態(tài),這個(gè)時(shí)候它不能進(jìn)入排隊(duì)狀態(tài),只有引起了阻塞的原因消失的時(shí)候,線程才可以繼續(xù)進(jìn)入排隊(duì)狀態(tài)等待CUP
處理。
3.3.5 死亡:處于死亡狀態(tài)的線程不具有繼續(xù)執(zhí)行的能力,線程死亡主要的原因是正常運(yùn)行的線程完成了全部工作,即執(zhí)行完了run()方法,另外就是被提前強(qiáng)制地終止了。
為了解決對共享存儲(chǔ)區(qū)的訪問沖突,Java引入了同步機(jī)制,現(xiàn)在讓我們來考察多個(gè)線程對共享資源的訪問,顯然同步機(jī)制已經(jīng)不夠了,因?yàn)樵谌我鈺r(shí)刻所要求的資源不一定已經(jīng)準(zhǔn)備好了被訪問,反過來,同一時(shí)刻準(zhǔn)備好了的資源也可能不止一個(gè)。為了解決這種情況下的訪問控制問題,Java引入了對阻塞機(jī)制的支持。
阻塞指的是暫停一個(gè)線程的執(zhí)行以等待某個(gè)條件發(fā)生(如某資源就緒),學(xué)過操作系統(tǒng)的同學(xué)對它一定已經(jīng)很熟悉了。Java提供了大量方法來支持阻塞包括sleep()方法、suspend()方法/yield()方法、wait()方法等。
4 結(jié)語
多線程雖然在編程中有著巨大的作用,但是多線程本身也有一些缺點(diǎn):如果有大量的線程,會(huì)影響性能,因?yàn)椴僮飨到y(tǒng)需要在它們之間切換;更多的線程需要更多的內(nèi)存空間;線程可能會(huì)給程序帶來更多“bug”,因此要小心使用;線程的中止需要考慮其對程序運(yùn)行的影響;通常塊模型數(shù)據(jù)是在多個(gè)線程間共享的,需要防止線程死鎖情況的
發(fā)生。
多線程的核心在于多個(gè)代碼塊并行執(zhí)行,本質(zhì)特點(diǎn)在于各代碼塊之間的代碼是亂序執(zhí)行的,因此,程序是否需要多線程、如何合理地利用多線程,就要視程序的需求而定,只有當(dāng)它完全符合多線程的特點(diǎn)時(shí),多線程機(jī)制對線程通信和線程管理的強(qiáng)大支持才能有用武之地。
參考文獻(xiàn)
[1] 孫學(xué)軍.“虛擬測震臺(tái)網(wǎng)”技術(shù)在廣西地區(qū)的應(yīng)用[J].地震地磁觀測與研究,2008,29(5):65-70.
[2] 孫學(xué)軍.GIS技術(shù)在地震學(xué)研究中的應(yīng)用[J].地球物理
學(xué)進(jìn)展,2005,20(1):160-164.
[3] 孫學(xué)軍.全國自動(dòng)地震速報(bào)系統(tǒng)介紹[J].地震地磁觀測與研究,2010,31(5):158-161.
[4] 邵維忠.面向?qū)ο蟮南到y(tǒng)分析[M].南寧:廣西科技出版社,1998.
[5] 吳吉義.軟件項(xiàng)目管理理論與案例分析[M].北京:中國電力出版社,2007.
[6] 欒躍.軟件開發(fā)項(xiàng)目管理[M].上海:上海交通大學(xué)出版社,2005.
作者簡介:金艷(1983-),女,浙江諸暨人,安徽省地震局助理工程師,研究方向:地震震相分析。
(責(zé)任編輯:黃銀芳)