一般來說,我們把正在計算機中執(zhí)行的程序叫做"進程"(Process) ,而不將其稱為程序(Program)。
所謂"線程"(Thread),是"進程"中某個單一順序的控制流。新興的操作系統(tǒng),如Mac,Windows NT,Windows 95等,大多采用多線程的概念,把線 程視為基本執(zhí)行單位。
線程也是Java中的相當(dāng)重要的組成部分之一。 甚至最簡單的Applet也是由多個線程來完成的。
在Java中, 任何一個Applet的paint()和update()方法都是由AWT(Abstract Window Toolkit)繪圖與事件處理線程調(diào)用的,而Applet 主要的里程碑方法——init(),start(),stop()和destory() ——是由執(zhí)行該Applet的應(yīng)用調(diào)用的。 單線程的概念沒有什么新的地方,真正有趣的是在一個程序中同時使用多個線程來完成不同的任務(wù)。
某些地方用輕量進程(Lightweig ht Process)來代替線程,線程與真正進程的相似性在于它們都是單一順序控制流。然而線程被認為輕量是由于它運行于整個程序的上下文內(nèi),能使用整個程序共有的資源和程序環(huán)境。
作為單一順序控制流,在運行的程序內(nèi)線程必須擁有一些資源作為必要的開銷。例如,必須有執(zhí)行堆棧和程序計數(shù)器在線程內(nèi)執(zhí)行的代碼只在它的上下文中起作用,因此某些地方用"執(zhí)行上下文"來代替"線程"。
線程屬性 為了正確有效地使用線程,必須理解線程的各個方面并了解Java 實時系統(tǒng)。 必須知道如何提供線程體、線程的生命周期、實時系統(tǒng)如何調(diào)度線程、線程組、什么是幽靈線程(Demo nThread)。
Java多線程程序需要我們具體的學(xué)習(xí)相關(guān)語法。
其中我們要了解相關(guān)的語法究竟有什么。很多重要的問題成本都在細節(jié),基本的語法就是Java多線程程序的細節(jié)。
希望大家有所收獲。 Java多線程程序中經(jīng)常用到的方法有以下幾個:run(),start(),wait(),sleep(),notify(),notifyAll(),yield(),join(),還有一個重要的關(guān)鍵字 synchronized。
下面分別對這些方法進行解釋: run()和start() 這兩個方法應(yīng)該都比較熟悉,把需要并行處理的代碼放在run()方法中,start()方法啟動線程將自動調(diào)用 run()方法,這是由Java的內(nèi)存機制規(guī)定的。并且run()方法必須是public訪問權(quán)限,返回值類型為void。
關(guān)鍵字Synchronized 這個關(guān)鍵字用于保護共享數(shù)據(jù),當(dāng)然前提是要分清哪些數(shù)據(jù)是共享數(shù)據(jù)。每個對象都有一個鎖標志,當(dāng)一個線程訪問該對象時,被Synchronized修飾的數(shù)據(jù)將被“上鎖”,阻止其他線程訪問。
當(dāng)前線程訪問完這部分數(shù)據(jù)后釋放鎖標志,其他線程就可以訪問了。 1。
public ThreadTest implements Runnable 2。{ 3。
public synchronized void run(){ 4。for(int i=0;i out。
println(" " + i); 7。} 8。
} 9。public static void main(String[] args) 10。
{ 11。Runnable r1 = new ThreadTest(); 12。
Runnable r2 = new ThreadTest(); 13。 Thread t1 = new Thread(r1); 14。
Thread t2 = new Thread(r2); 15。t1。
start(); 16。t2。
start(); 17。} 18。
} 以上這段程序中的 i 變量并不是共享數(shù)據(jù),也就是這里的Synchronized關(guān)鍵字并未起作用。 因為t1,t2兩個線程是兩個對象(r1,r2)的線程。
不同的對象其數(shù)據(jù)是不同的,所以r1和r2兩個對象的i變量是并不是共享數(shù)據(jù)。 當(dāng)把代碼改成如下:Synchronized關(guān)鍵字才會起作用 19。
Runnable r = new ThreadTest(); 20。 Thread t1 = new Thread(r); 21。
Thread t2 = new Thread(r); 22。t1。
start(); 23。t2。
start(); 以上就是對Java多線程程序的詳細介紹。
為什么會排隊等待? 下面的這個簡單的 Java 程序完成四項不相關(guān)的任務(wù)。
這樣的程序有單個控制線程,控制在這四個任務(wù)之間線性地移動。此外,因為所需的資源 — 打印機、磁盤、數(shù)據(jù)庫和顯示屏 -- 由于硬件和軟件的限制都有內(nèi)在的潛伏時間,所以每項任務(wù)都包含明顯的等待時間。
因此,程序在訪問數(shù)據(jù)庫之前必須等待打印機完成打印文件的任務(wù),等等。如果您正在等待程序的完成,則這是對計算資源和您的時間的一種拙劣使用。
改進此程序的一種方法是使它成為多線程的。 在本例中,每項任務(wù)在開始之前必須等待前一項任務(wù)完成,即使所涉及的任務(wù)毫不相關(guān)也是這樣。
但是,在現(xiàn)實生活中,我們經(jīng)常使用多線程模型。我們在處理某些任務(wù)的同時也可以讓孩子、配偶和父母完成別的任務(wù)。
例如,我在寫信的同時可能打發(fā)我的兒子去郵局買郵票。用軟件術(shù)語來說,這稱為多個控制(或執(zhí)行)線程。
限制線程優(yōu)先級和調(diào)度 Java 線程模型涉及可以動態(tài)更改的線程優(yōu)先級。
本質(zhì)上,線程的優(yōu)先級是從 1 到 10 之間的一個數(shù)字,數(shù)字越大表明任務(wù)越緊急。JVM 標準首先調(diào)用優(yōu)先級較高的線程,然后才調(diào)用優(yōu)先級較低的線程。
但是,該標準對具有相同優(yōu)先級的線程的處理是隨機的。 如何處理這些線程取決于基層的操作系統(tǒng)策略。
在某些情況下,優(yōu)先級相同的線程分時運行;在另一些情況下,線程將一直運行到結(jié)束。請記住,Java 支持 10 個優(yōu)先級,基層操作系統(tǒng)支持的優(yōu)先級可能要少得多,這樣會造成一些混亂。
因此,只能將優(yōu)先級作為一種很粗略的工具使用。 最后的控制可以通過明智地使用 yield() 函數(shù)來完成。
通常情況下,請不要依靠線程優(yōu)先級來控制線程的狀態(tài)。 小結(jié) 本文說明了在 Java 程序中如何使用線程。
像是否應(yīng)該使用線程這樣的更重要的問題在很大程序上取決于手頭的應(yīng)用程序。決定是否在應(yīng)用程序中使用多線程的一種方法是,估計可以并行運行的代碼量。
并記住以下幾點: 使用多線程不會增加 CPU 的能力。但是如果使用 JVM 的本地線程實現(xiàn),則不同的線程可以在不同的處理器上同時運行(在多 CPU 的機器中),從而使多 CPU 機器得到充分利用。
如果應(yīng)用程序是計算密集型的,并受 CPU 功能的制約,則只有多 CPU 機器能夠從更多的線程中受益。 當(dāng)應(yīng)用程序必須等待緩慢的資源(如網(wǎng)絡(luò)連接或數(shù)據(jù)庫連接)時,或者當(dāng)應(yīng)用程序是非交互式的時,多線程通常是有利的。
基于 Internet 的軟件有必要是多線程的;否則,用戶將感覺應(yīng)用程序反映遲鈍。例如,當(dāng)開發(fā)要支持大量客戶機的服務(wù)器時,多線程可以使編程較為容易。
在這種情況下,每個線程可以為不同的客戶或客戶組服務(wù),從而縮短了響應(yīng)時間。 某些程序員可能在 C 和其他語言中使用過線程,在那些語言中對線程沒有語言支持。
這些程序員可能通常都被搞得對線程失去了信心。
一、主內(nèi)存與工作內(nèi)存 1。
Java 內(nèi)存模型的主要目標是定義程序中各個變量的訪問規(guī)則。此處的變量與Java編程時所說的變量不一樣,指包括了實例字段、靜態(tài)字段和構(gòu)成數(shù)組對象的元素,但是不包括局部變量與方法參數(shù),因為它們是線程私有的,不會被共享。
2。Java內(nèi)存模型中規(guī)定了所有的變量都存儲在主內(nèi)存中,每條線程還有自己的虛擬內(nèi)存。
線程的虛擬內(nèi)存中保存了該線程使用到的變量到主內(nèi)存副本拷貝。線程對變量的所有操作(讀取、賦值)都必須在自己的虛擬內(nèi)存中進行,而不能直接讀寫主內(nèi)存中的變量。
不同線程之間無法直接訪問對方虛擬內(nèi)存中的變量,線程間變量值的傳遞均需要在主內(nèi)存來完成。 二、內(nèi)存間交互操作 關(guān)于主內(nèi)存與工作內(nèi)存之間的具體交互協(xié)議,即一個變量如何從主內(nèi)存拷貝到工作內(nèi)存、如何從工作內(nèi)存同步到主內(nèi)存之間的實現(xiàn)細節(jié),Java內(nèi)存模型定義了以下八種操作來完成: ? lock(鎖定):作用于主內(nèi)存的變量,把一個變量標識為一條線程獨占狀態(tài)。
? unlock(解鎖):作用于主內(nèi)存變量,把一個處于鎖定狀態(tài)的變量釋放出來,釋放后 的變量才可以被其他線程鎖定。 。
線程是Java語言的一個部分,而且是Java的最強大的功能之一。
究竟什么是線程,為什么要開發(fā)基于線程的應(yīng)用程序?在本文中,我們將深入了解一下線程的用法,以及使用線程的一些技術(shù)。在我們開始講述線程之前,最好先了解一下有關(guān)背景知識和分析一下線程的工作原理。
當(dāng)程序員一開始開發(fā)應(yīng)用程序時,這些應(yīng)用程序只能在一個時間內(nèi)完成一件事情。應(yīng)用程序從主程序開始執(zhí)行,直到運行結(jié)束,像 Fortran/Cobol/Basic這些語言均是如此。
隨著時間的推移,計算機發(fā)展到可以在同一時間段內(nèi)運行不止一個應(yīng)用程序的時代了,但是應(yīng)用程序運行時仍然是串行的,即從開始運行到結(jié)束,下一條指令接著上一條指令執(zhí)行。 到最近,程序發(fā)展到可以在執(zhí)行時,以若干個線程的形式運行。
Java就具有運行多線程的能力,可以在同一時間段內(nèi)進行幾個操作,這就意味著給定的操作不必等到另外一個操作結(jié)束之后,才能開始。而且對某個操作可以指定更高一級的優(yōu)先級。
不少程序語言,包括ADA, Modula-2和C/C++,已經(jīng)可以提供對線程的支持。 同這些語言相比,Java的特點是從最底層開始就對線程提供支持。
除此以外,標準的Java類是可重入的,允許在一個給定的應(yīng)用程序中由多個線程調(diào)用同一方法,而線程彼此之間又互不干擾。Java的這些特點為多線程應(yīng)用程序的設(shè)計奠定了基礎(chǔ)。
什么是線程?究竟什么是線程呢?正如在圖A中所示,一個線程是給定的指令的序列 (你所編寫的代碼),一個棧(在給定的方法中定義的變量),以及一些共享數(shù)據(jù)(類一級的變量)。 線程也可以從全局類中訪問靜態(tài)數(shù)據(jù)。
進程是程序在處理機中的一次運行。
一個進程既包括其所要執(zhí)行的指令,也包括了執(zhí)行指令所需的系統(tǒng)資源,不同進程所占用的系統(tǒng)資源相對獨立。所以進程是重量級的任務(wù),它們之間的通信和轉(zhuǎn)換都需要操作系統(tǒng)付出較大的開銷。
線程是進程中的一個實體,是被系統(tǒng)獨立調(diào)度和分派的基本單位。線程自己基本上不擁有系統(tǒng)資源,但它可以與同屬一個進程的其他線程共享進程所擁有的全部資源。
所以線程是輕量級的任務(wù),它們之間的通信和轉(zhuǎn)換只需要較小的系統(tǒng)開銷。 Java支持多線程編程,因此用Java編寫的應(yīng)用程序可以同時執(zhí)行多個任務(wù)。
Java的多線程機制使用起來非常方便,用戶只需關(guān)注程序細節(jié)的實現(xiàn),而不用擔(dān)心后臺的多任務(wù)系統(tǒng)。 Java語言里,線程表現(xiàn)為線程類。
Thread線程類封裝了所有需要的線程操作控制。在設(shè)計程序時,必須很清晰地區(qū)分開線程對象和運行線程,可以將線程對象看作是運行線程的控制面板。
在線程對象里有很多方法來控制一個線程是否運行,睡眠,掛起或停止。線程類是控制線程行為的唯一的手段。
一旦一個Java程序啟動后,就已經(jīng)有一個線程在運行。可通過調(diào)用Thread.currentThread方法來查看當(dāng)前運行的是哪一個線程。
class ThreadTest{ public static void main(String args[]){ Thread t = Thread.currentThread(); t.setName("單線程"); //對線程取名為"單線程" t.setPriority(8); //設(shè)置線程優(yōu)先級為8,最高為10,最低為1,默認為5 System.out.println("The running thread: " + t); // 顯示線程信息 try{ for(int i=0;i<3;i++){ System.out.println("Sleep time " + i); Thread.sleep(100); // 睡眠100毫秒 } }catch(InterruptedException e){// 捕獲異常 System.out.println("thread has wrong"); } } } 多線程的實現(xiàn)方法 繼承Thread類 可通過繼承Thread類并重寫其中的run()方法來定義線程體以實現(xiàn)線程的具體行為,然后創(chuàng)建該子類的對象以創(chuàng)建線程。在繼承Thread類的子類ThreadSubclassName中重寫run()方法來定義線程體的一般格式為: public class ThreadSubclassName extends Thread{ public ThreadSubclassName(){ 。
.. // 編寫子類的構(gòu)造方法,可缺省 } public void run(){ 。.. // 編寫自己的線程代碼 } } 用定義的線程子類ThreadSubclassName創(chuàng)建線程對象的一般格式為: ThreadSubclassName ThreadObject = new ThreadSubclassName(); 然后,就可啟動該線程對象表示的線程: ThreadObject.start(); //啟動線程 應(yīng)用繼承類Thread的方法實現(xiàn)多線程的程序。
本程序創(chuàng)建了三個單獨的線程,它們分別打印自己的“Hello World!”。 class ThreadDemo extends Thread{ private String whoami; private int delay; public ThreadDemo(String s,int d){ whoami=s; delay=d; } public void run(){ try{ sleep(delay); }catch(InterruptedException e){ } System.out.println("Hello World!" + whoami + " " + delay); } } public class MultiThread{ public static void main(String args[]){ ThreadDemo t1,t2,t3; t1 = new ThreadDemo("Thread1", (int)(Math.random()*2000)); t2 = new ThreadDemo("Thread2", (int)(Math.random()*2000)); t3 = new ThreadDemo("Thread3", (int)(Math.random()*2000)); t1.start(); t2.start(); t3.start(); } } 實現(xiàn)Runnable接口 編寫多線程程序的另一種的方法是實現(xiàn)Runnable接口。
在一個類中實現(xiàn)Runnable接口(以后稱實現(xiàn)Runnable接口的類為Runnable類),并在該類中定義run()方法,然后用帶有Runnable參數(shù)的Thread類構(gòu)造方法創(chuàng)建線程。創(chuàng)建線程對象可用下面的兩個步驟來完成:(1)生成Runnable類ClassName的對象 ClassName RunnableObject = new ClassName();(2)用帶有Runnable參數(shù)的Thread類構(gòu)造方法創(chuàng)建線程對象。
新創(chuàng)建的線程的指針將指向Runnable類的實例。用該Runnable類的實例為線程提供 run()方法---線程體。
Thread ThreadObject = new Thread(RunnableObject); 然后,就可啟動線程對象ThreadObject表示的線程:ThreadObject.start(); 在Thread類中帶有Runnable接口的構(gòu)造方法有: public Thread(Runnable target); public Thread(Runnable target, String name); public Thread(String name); public Thread(ThreadGroup group,Runnable target); public Thread(ThreadGroup group,Runnable target, String name); 其中,參數(shù)Runnable target表示該線程執(zhí)行時運行target的run()方法,String name以指定名字構(gòu)造線程,ThreadGroup group表示創(chuàng)建線程組。用Runnable接口實現(xiàn)的多線程。
class TwoThread implements Runnable{ TwoThread(){ Thread t1 = Thread.currentThread(); t1.setName("第一主線程"); System.out.println("正在運行的線程: " + t1); Thread t2 = new Thread(this,"第二線程"); System.out.println("創(chuàng)建第二線程"); t2.start(); try{ System.out.println("第一線程休眠"); Thread.sleep(3000); }catch(InterruptedException e){ System.out.println("第一線程有錯"); } System.out.println("第一線程退出"); } public void run(){ try{ for(int i = 0;i < 5;i++){ System.out.println(“第二線程的。
聲明:本網(wǎng)站尊重并保護知識產(chǎn)權(quán),根據(jù)《信息網(wǎng)絡(luò)傳播權(quán)保護條例》,如果我們轉(zhuǎn)載的作品侵犯了您的權(quán)利,請在一個月內(nèi)通知我們,我們會及時刪除。
蜀ICP備2020033479號-4 Copyright ? 2016 學(xué)習(xí)鳥. 頁面生成時間:3.112秒