多線程的java 程序如何編寫?
Java 給多線程編程提供了內(nèi)置的支持。 一條線程指的是進(jìn)程中一個(gè)單一順序的控制流,一個(gè)進(jìn)程中可以并發(fā)多個(gè)線程,每條線程并行執(zhí)行不同的任務(wù)。
新建狀態(tài):
使用 new 關(guān)鍵字和 Thread 類或其子類建立一個(gè)線程對象后,該線程對象就處于新建狀態(tài)。它保持這個(gè)狀態(tài)直到程序 start() 這個(gè)線程。
就緒狀態(tài):
當(dāng)線程對象調(diào)用了start()方法之后,該線程就進(jìn)入就緒狀態(tài)。就緒狀態(tài)的線程處于就緒隊(duì)列中,要等待JVM里線程調(diào)度器的調(diào)度。
運(yùn)行狀態(tài):
如果就緒狀態(tài)的線程獲取 CPU 資源,就可以執(zhí)行 run(),此時(shí)線程便處于運(yùn)行狀態(tài)。處于運(yùn)行狀態(tài)的線程最為復(fù)雜,它可以變?yōu)樽枞麪顟B(tài)、就緒狀態(tài)和死亡狀態(tài)。
阻塞狀態(tài):
如果一個(gè)線程執(zhí)行了sleep(睡眠)、suspend(掛起)等方法,失去所占用資源之后,該線程就從運(yùn)行狀態(tài)進(jìn)入阻塞狀態(tài)。在睡眠時(shí)間已到或獲得設(shè)備資源后可以重新進(jìn)入就緒狀態(tài)??梢苑譃槿N:
等待阻塞:運(yùn)行狀態(tài)中的線程執(zhí)行 wait() 方法,使線程進(jìn)入到等待阻塞狀態(tài)。
同步阻塞:線程在獲取 同步鎖失敗(因?yàn)橥芥i被其他線程占用)。
其他阻塞:通過調(diào)用線程的 sleep() 或 join() 發(fā)出了 I/O 請求時(shí),線程就會進(jìn)入到阻塞狀態(tài)。當(dāng)sleep() 狀態(tài)超時(shí),join() 等待線程終止或超時(shí),或者 I/O 處理完畢,線程重新轉(zhuǎn)入就緒狀態(tài)。
死亡狀態(tài):
一個(gè)運(yùn)行狀態(tài)的線程完成任務(wù)或者其他終止條件發(fā)生時(shí),該線程就切換到終止?fàn)顟B(tài)。
java多線程編程中涉及的基礎(chǔ)知識點(diǎn)?
線程設(shè)計(jì)在軟件開發(fā)領(lǐng)域中是非常常見的一個(gè)設(shè)計(jì)構(gòu)成,今天霍營北大青鳥就一起來了解一下,java多線程編程中都涉及到了哪些基礎(chǔ)知識點(diǎn)。
順序
用于表示多個(gè)操作“依次處理”。比如把十個(gè)操作交給一個(gè)人來處理時(shí),這個(gè)人要一個(gè)一個(gè)地按順序來處理
并行
用于標(biāo)識多個(gè)操作“同時(shí)處理”。比如十個(gè)操作分給兩個(gè)人處理時(shí),這兩個(gè)人就會并行來處理。
并發(fā)
相對于順序和并行來說比較抽象,用于表示“將一個(gè)操作分割成多個(gè)部分并且允許無序處理”。比如將十個(gè)操作分成相對獨(dú)立的兩類,這樣便能夠開始并發(fā)處理了。如果一個(gè)人來處理,這個(gè)人就是順序處理分開的并發(fā)操作,而如果是兩個(gè)人,這兩個(gè)人就可以并行處理同一個(gè)操作。
總結(jié)
多線程程序都是并發(fā)處理的。如果CPU只有一個(gè),那么并發(fā)處理就是順序執(zhí)行的,而如果有多個(gè)CPU,那么并發(fā)處理就可能會并行運(yùn)行。
等待隊(duì)列
所有實(shí)例都擁有一個(gè)等待隊(duì)列,它是在實(shí)例的wait方法執(zhí)行后停止操作的線程隊(duì)列。就好比為每個(gè)實(shí)例準(zhǔn)備的線程休息室
在執(zhí)行wait方法后,線程便會暫停操作,進(jìn)入等待隊(duì)列這個(gè)休息室。除非發(fā)生下列某一情況,否則線程會一直在等待隊(duì)列中休眠。
有其他線程的notify方法來喚醒線程
有其他線程的notifyAll方法來喚醒線程
有其他線程的interrupt方法來喚醒線程
wait方法超時(shí)
notify方法
該方法會將等待隊(duì)列中的一個(gè)線程去除。同wait方法一樣,若要執(zhí)行notify方法,線程也必須持有要調(diào)用的實(shí)例的鎖。
notifyAll方法
notify方法僅喚醒一個(gè)線程,而notifyAll則喚醒所有線程,這是兩者之間的區(qū)別
同wait方法和notify方法一樣,notifyAll方法也只能由持有要調(diào)用的實(shí)例鎖的線程調(diào)用
notify和notifyAll選擇
notify方法和notifyAll方法非常相似,到底該使用哪個(gè)?
實(shí)際上,這很難選擇,由于notify喚醒的線程較少,所以處理速度要比使用notifyAll時(shí)快。但使用notify時(shí),如果處理不好,程序便可能會停止。一般來說,使用notifyAll時(shí)的代碼要比使用notify時(shí)的更為健壯。
什么是Java多線程編程?
一、 什么是多線程:
我們現(xiàn)在所使用操作系統(tǒng)都是多任務(wù)操作系統(tǒng)(早期使用的DOS操作系統(tǒng)為單任務(wù)操作系統(tǒng)),多任務(wù)操作指在同一時(shí)刻可以同時(shí)做多件事(可以同時(shí)執(zhí)行多個(gè)程序)。
多進(jìn)程:每個(gè)程序都是一個(gè)進(jìn)程,在操作系統(tǒng)中可以同時(shí)執(zhí)行多個(gè)程序,多進(jìn)程的目的是為了有效的使用CPU資源,每開一個(gè)進(jìn)程系統(tǒng)要為該進(jìn)程分配相關(guān)的系統(tǒng)資源(內(nèi)存資源)
多線程:線程是進(jìn)程內(nèi)部比進(jìn)程更小的執(zhí)行單元(執(zhí)行流|程序片段),每個(gè)線程完成一個(gè)任務(wù),每個(gè)進(jìn)程內(nèi)部包含了多個(gè)線程每個(gè)線程做自己的事情,在進(jìn)程中的所有線程共享該進(jìn)程的資源;
主線程:在進(jìn)程中至少存在一個(gè)主線程,其他子線程都由主線程開啟,主線程不一定在其他線程結(jié)束后結(jié)束,有可能在其他線程結(jié)束前結(jié)束。Java中的主線程是main線程,是Java的main函數(shù);
二、 Java中實(shí)現(xiàn)多線程的方式:
繼承Thread類來實(shí)現(xiàn)多線程:
當(dāng)我們自定義的類繼承Thread類后,該類就為一個(gè)線程類,該類為一個(gè)獨(dú)立的執(zhí)行單元,線程代碼必須編寫在run()方法中,run方法是由Thread類定義,我們自己寫的線程類必須重寫run方法。
run方法中定義的代碼為線程代碼,但run方法不能直接調(diào)用,如果直接調(diào)用并沒有開啟新的線程而是將run方法交給調(diào)用的線程執(zhí)行
要開啟新的線程需要調(diào)用Thread類的start()方法,該方法自動開啟一個(gè)新的線程并自動執(zhí)行run方法中的內(nèi)容
請點(diǎn)擊輸入圖片描述
結(jié)果:
請點(diǎn)擊輸入圖片描述
java多線程的啟動順序不一定是線程執(zhí)行的順序,各個(gè)線程之間是搶占CPU資源執(zhí)行的,所有有可能出現(xiàn)與啟動順序不一致的情況。
CPU的調(diào)用策略:
如何使用CPU資源是由操作系統(tǒng)來決定的,但操作系統(tǒng)只能決定CPU的使用策略不能控制實(shí)際獲得CPU執(zhí)行權(quán)的程序。
線程執(zhí)行有兩種方式:
1.搶占式:
目前PC機(jī)中使用最多的一種方式,線程搶占CPU的執(zhí)行權(quán),當(dāng)一個(gè)線程搶到CPU的資源后并不是一直執(zhí)行到此線程執(zhí)行結(jié)束,而是執(zhí)行一個(gè)時(shí)間片后讓出CPU資源,此時(shí)同其他線程再次搶占CPU資源獲得執(zhí)行權(quán)。
2.輪循式;
每個(gè)線程執(zhí)行固定的時(shí)間片后讓出CPU資源,以此循環(huán)執(zhí)行每個(gè)線程執(zhí)行相同的時(shí)間片后讓出CPU資源交給下一個(gè)線程執(zhí)行。
希望對您有所幫助!~
java如何實(shí)現(xiàn)多線程編程
1、public class MyThread extends Thread{//重寫run()方法public void run(){ //多線程要做的事}public static void main(String args[]){ MyThread m1 = new MyThread(); MyThread m2 = new MyThread(); m1.start(); m2.start();}} 2、public class NThread Runable{ //實(shí)現(xiàn)run()方法 public void run(){ //多線程要做的事 } public static void main(String args[]){ NThread nt = new NThread(); new Thread(nt,"nt1_name").start(); new Thread(nt,"nt2_name").start(); }}
java多線程開發(fā)的同步機(jī)制有哪些
Java同步
標(biāo)簽: 分類:
一、關(guān)鍵字:
thread(線程)、thread-safe(線程安全)、(并發(fā)的)
(同步的)、(異步的)、
volatile(易變的)、atomic(原子的)、share(共享)
二、總結(jié)背景:
一次讀寫共享文件編寫,嚯,好家伙,竟然揪出這些零碎而又是一路的知識點(diǎn)。于是乎,Google和翻閱了《Java參考大全》、《Effective Java Second Edition》,特此總結(jié)一下供日后工作學(xué)習(xí)參考。
三、概念:
1、 什么時(shí)候必須同步?什么叫同步?如何同步?
要跨線程維護(hù)正確的可見性,只要在幾個(gè)線程之間共享非 final 變量,就必須使用 (或 volatile)以確保一個(gè)線程可以看見另一個(gè)線程做的更改。
為了在線程之間進(jìn)行可靠的通信,也為了互斥訪問,同步是必須的。這歸因于java語言規(guī)范的內(nèi)存模型,它規(guī)定了:一個(gè)線程所做的變化何時(shí)以及如何變成對其它線程可見。
因?yàn)槎嗑€程將異步行為引進(jìn)程序,所以在需要同步時(shí),必須有一種方法強(qiáng)制進(jìn)行。例如:如果2個(gè)線程想要通信并且要共享一個(gè)復(fù)雜的數(shù)據(jù)結(jié)構(gòu),如鏈表,此時(shí)需要
確保它們互不沖突,也就是必須阻止B線程在A線程讀數(shù)據(jù)的過程中向鏈表里面寫數(shù)據(jù)(A獲得了鎖,B必須等A釋放了該鎖)。
為了達(dá)到這個(gè)目的,java在一個(gè)舊的的進(jìn)程同步模型——監(jiān)控器(Monitor)的基礎(chǔ)上實(shí)現(xiàn)了一個(gè)巧妙的方案:監(jiān)控器是一個(gè)控制機(jī)制,可以認(rèn)為是一個(gè)
很小的、只能容納一個(gè)線程的盒子,一旦一個(gè)線程進(jìn)入監(jiān)控器,其它的線程必須等待,直到那個(gè)線程退出監(jiān)控為止。通過這種方式,一個(gè)監(jiān)控器可以保證共享資源在
同一時(shí)刻只可被一個(gè)線程使用。這種方式稱之為同步。(一旦一個(gè)線程進(jìn)入一個(gè)實(shí)例的任何同步方法,別的線程將不能進(jìn)入該同一實(shí)例的其它同步方法,但是該實(shí)例
的非同步方法仍然能夠被調(diào)用)。
錯(cuò)誤的理解:同步嘛,就是幾個(gè)線程可以同時(shí)進(jìn)行訪問。
同步和多線程關(guān)系:沒多線程環(huán)境就不需要同步;有多線程環(huán)境也不一定需要同步。
鎖提供了兩種主要特性:互斥(mutual exclusion) 和可見性()。
互斥即一次只允許一個(gè)線程持有某個(gè)特定的鎖,因此可使用該特性實(shí)現(xiàn)對共享數(shù)據(jù)的協(xié)調(diào)訪問協(xié)議,這樣,一次就只有一個(gè)線程能夠使用該共享數(shù)據(jù)。
可見性要更加復(fù)雜一些,documents它必須確保釋放鎖之前對共享數(shù)據(jù)做出的更改對于隨后獲得該鎖的另一個(gè)線程是可見的 —— 如果沒有同步機(jī)制提供的這種可見性保證,線程看到的共享變量可能是修改前的值或不一致的值,這將引發(fā)許多嚴(yán)重問題
小結(jié):為了防止多個(gè)線程并發(fā)對同一數(shù)據(jù)的修改,所以需要同步,否則會造成數(shù)據(jù)不一致(就是所謂的:線程安全。如java集合框架中Hashtable和
Vector是線程安全的。我們的大部分程序都不是線程安全的,因?yàn)闆]有進(jìn)行同步,而且我們沒有必要,因?yàn)榇蟛糠智闆r根本沒有多線程環(huán)境)。
2、 什么叫原子的(原子操作)?
Java原子操作是指:不會被打斷地的操作。(就是做到互斥 和可見性??。?
那難道原子操作就可以真的達(dá)到線程安全同步效果了嗎?實(shí)際上有一些原子操作不一定是線程安全的。
那么,原子操作在什么情況下不是線程安全的呢?也許是這個(gè)原因?qū)е碌模簀ava線程允許線程在自己的內(nèi)存區(qū)保存變量的副本。允許線程使用本地的私有拷貝進(jìn)
行工作而非每次都使用主存的值是為了提高性能(本人愚見:雖然原子操作是線程安全的,可各線程在得到變量(讀操作)后,就是各自玩
弄自己的副本了,更新操作(寫操作)因未寫入主存中,導(dǎo)致其它線程不可見)。
那該如何解決呢?因此需要通過java同步機(jī)制。
在java中,32位或者更少位數(shù)的賦值是原子的。在一個(gè)32位的硬件平臺上,除了double和long型的其它原始類型通常都
是使用32位進(jìn)行表示,而double和long通常使用64位表示。另外,對象引用使用本機(jī)指針實(shí)現(xiàn),通常也是32位的。對這些32位的類型的操作是原
子的。
這些原始類型通常使用32位或者64位表示,這又引入了另一個(gè)小小的神話:原始類型的大小是由語言保證的。這是不對的。java語言保證的是原始類型的表
數(shù)范圍而非JVM中的存儲大小。因此,int型總是有相同的表數(shù)范圍。在一個(gè)JVM上可能使用32位實(shí)現(xiàn),而在另一個(gè)JVM上可能是64位的。在此再次強(qiáng)
調(diào):在所有平臺上被保證的是表數(shù)范圍,32位以及更小的值的操作是原子的。
3、 不要搞混了:同步、異步
舉個(gè)例子:普通B/S模式(同步)AJAX技術(shù)(異步)
同步:提交請求->等待服務(wù)器處理->處理完返回 這個(gè)期間客戶端瀏覽器不能干任何事
異步:請求通過事件觸發(fā)->服務(wù)器處理(這是瀏覽器仍然可以作其他事情)->處理完畢
可見,彼“同步”非此“同步”——我們說的java中的那個(gè)共享數(shù)據(jù)同步()
一個(gè)同步的對象是指行為(動作),一個(gè)是同步的對象是指物質(zhì)(共享數(shù)據(jù))。
4、 Java同步機(jī)制有4種實(shí)現(xiàn)方式:(部分引用網(wǎng)上資源)
① ② ( ) ③ wait() 與 notify() ④ volatile
目的:都是為了解決多線程中的對同一變量的訪問沖突
保證不同線程擁有不同實(shí)例,相同線程一定擁有相同的實(shí)例,即為每一個(gè)使用該變量的線程提供一個(gè)該變量值的副本,每一個(gè)線程都可以獨(dú)立改變自己的副本,而不是與其它線程的副本沖突。
優(yōu)勢:提供了線程安全的共享對象
與其它同步機(jī)制的區(qū)別:同步機(jī)制是為了同步多個(gè)線程對相同資源的并發(fā)訪問,是為了多個(gè)線程之間進(jìn)行通信;而 是隔離多個(gè)線程的數(shù)據(jù)共享,從根本上就不在多個(gè)線程之間共享資源,這樣當(dāng)然不需要多個(gè)線程進(jìn)行同步了。
volatile
volatile 修飾的成員變量在每次被線程訪問時(shí),都強(qiáng)迫從共享內(nèi)存中重讀該成員變量的值。而且,當(dāng)成員變量發(fā)生變化時(shí),強(qiáng)迫線程將變化值回寫到共享內(nèi)存。
優(yōu)勢:這樣在任何時(shí)刻,兩個(gè)不同的線程總是看到某個(gè)成員變量的同一個(gè)值。
緣由:Java
語言規(guī)范中指出,為了獲得*速度,允許線程保存共享成員變量的私有拷貝,而且只當(dāng)線程進(jìn)入或者離開同步代碼塊時(shí)才與共享成員變量的原
始值對比。這樣當(dāng)多個(gè)線程同時(shí)與某個(gè)對象交互時(shí),就必須要注意到要讓線程及時(shí)的得到共享成員變量的變化。而 volatile
關(guān)鍵字就是提示 VM :對于這個(gè)成員變量不能保存它的私有拷貝,而應(yīng)直接與共享成員變量交互。
使用技巧:在兩個(gè)或者更多的線程訪問的成員變量上使用 volatile 。當(dāng)要訪問的變量已在 代碼塊中,或者為常量時(shí),不必使用。
線程為了提高效率,將某成員變量(如A)拷貝了一份(如B),線程中對A的訪問其實(shí)訪問的是B。只在某些動作時(shí)才進(jìn)行A和B的同步,因此存在A和B不一致
的情況。volatile就是用來避免這種情況的。
volatile告訴jvm,它所修飾的變量不保留拷貝,直接訪問主內(nèi)存中的(讀操作多時(shí)使用較好;線程間需要通信,本條做不到)
Volatile 變量具有 的可見性特性,但是不具備原子特性。這就是說線程能夠自動發(fā)現(xiàn) volatile
變量的*值。Volatile
變量可用于提供線程安全,但是只能應(yīng)用于非常有限的一組用例:多個(gè)變量之間或者某個(gè)變量的當(dāng)前值與修改后值
之間沒有約束。
您只能在有限的一些情形下使用 volatile 變量替代鎖。要使 volatile 變量提供理想的線程安全,必須同時(shí)滿足下面兩個(gè)條件:
對變量的寫操作不依賴于當(dāng)前值;該變量沒有包含在具有其他變量的不變式中。
sleep() vs wait()
sleep是線程類(Thread)的方法,導(dǎo)致此線程暫停執(zhí)行指定時(shí)間,把執(zhí)行機(jī)會給其他線程,但是監(jiān)控狀態(tài)依然保持,到時(shí)后會自動恢復(fù)。調(diào)用sleep不會釋放對象鎖。
wait是Object類的方法,對此對象調(diào)用wait方法導(dǎo)致本線程放棄對象鎖,進(jìn)入等待此對象的等待鎖定池,只有針對此對象發(fā)出notify方法(或notifyAll)后本線程才進(jìn)入對象鎖定池準(zhǔn)備獲得對象鎖進(jìn)入運(yùn)行狀態(tài)。
(如果變量被聲明為volatile,在每次訪問時(shí)都會和主存一致;如果變量在同步方法或者同步塊中被訪問,當(dāng)在方法或者塊的入口處獲得鎖以及方法或者塊退出時(shí)釋放鎖時(shí)變量被同步。)
java多線程編程
樓主出現(xiàn)問題有2點(diǎn):
1. wake() 這個(gè)方法也要同步啊,加關(guān)鍵字 ;
2. *次調(diào)用st()方法后,available應(yīng)該保持不變,這樣才能保證線程b也打印..start,所以加個(gè)if判斷一下就ok啦。
public class ABC {
boolean available=false;
String name;
int count=0;
public ABC(String name){
this.name=name;
}
public void st(){
System.out.println("... start.");
count++;
if(count>1){
available=true;
}
try{
wait();
}catch(Exception e){}
System.out.println("... end.");
}
public void end(){
System.out.println("... end.");
}
public void wake() {
notifyAll();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ABC x=new ABC("haha");
a=new (x);
b=new (x);
C c=new C(x);
(new Thread(a)).start();
(new Thread(b)).start();
(new Thread(c)).start();
}
}
class Runnable{
ABC abc;
public (ABC abc){
this.abc=abc;
}
public void run(){
if(!abc.available){
abc.st();
}
else abc.end();
}
}
class C Runnable{
ABC abc;
public C(ABC abc){
this.abc=abc;
}
public void run(){
try{
Thread.sleep(1000);
// System.out.println("sjlfsj jfsdl j"); //驗(yàn)證是否執(zhí)行到這里
}catch( e){};
abc.wake();
}
}
JAVA多線程編程的幾種表示方法
創(chuàng)建線程有兩種方法:繼承Thread類和實(shí)現(xiàn)Runnable接口。
方法一:繼承 Thread 類,覆蓋方法 run(),我們在創(chuàng)建的 Thread 類的子類中重寫 run() ,加入線程所要執(zhí)行的代碼即可。下面是一個(gè)例子:
public class MyThread extends Thread {
int count= 1, number;
public MyThread(int num) {
number = num;
System.out.println("創(chuàng)建線程 " + number);
}
public void run() {
while(true) {
System.out.println("線程 " + number + ":計(jì)數(shù) " + count);
if(++count== 6) return;
}
}
public static void main(String args[]) {
for(int i = 0; i < 5; i++) new MyThread(i+1).start();
}
}
方法二:實(shí)現(xiàn) Runnable 接口
Runnable 接口只有一個(gè)方法 run(),我們聲明自己的類實(shí)現(xiàn) Runnable 接口并提供這一方法,將我們的線程代碼寫入其中,就完成了這一部分的任務(wù)。但是 Runnable 接口并沒有任何對線程的支持,我們還必須創(chuàng)建 Thread 類的實(shí)例,這一點(diǎn)通過 Thread 類的構(gòu)造函數(shù)public Thread(Runnable target);來實(shí)現(xiàn)。下面是一個(gè)例子:
public class MyThread Runnable {
int count= 1, number;
public MyThread(int num) {
number = num;
System.out.println("創(chuàng)建線程 " + number);
}
public void run() {
while(true) {
System.out.println("線程 " + number + ":計(jì)數(shù) " + count);
if(++count== 6) return;
}
}
public static void main(String args[]) {
for(int i = 0; i < 5; i++) new Thread(new MyThread(i+1)).start();
}
}
兩種方法各有千秋,可以靈活運(yùn)用。
什么是多線程編程
多線程編程技術(shù)是Java語言的重要特點(diǎn)。多線程編程的含義是將程序任務(wù)分成幾個(gè)并行的子任務(wù)。特別是在網(wǎng)絡(luò)編程中,你會發(fā)現(xiàn)很多功能是可以并發(fā)執(zhí)行的。
比如網(wǎng)絡(luò)傳輸速度較慢、用戶輸入速度較慢,你可以用兩個(gè)獨(dú)立的線程去完成這兩個(gè)功能,而不影響正常的顯示或其它功能。
多線程是與單線程比較而言的,普通的Windows采用單線程程序結(jié)構(gòu),其工作原理是:主程序有一個(gè)消息循環(huán),不斷從消息隊(duì)列中讀入消息來決定下一步所要干的事情,一般是針對一個(gè)函數(shù),只有等這個(gè)函數(shù)執(zhí)行完之后,主程序才能接收另外的消息來執(zhí)行。比如子函數(shù)功能是在讀一個(gè)網(wǎng)絡(luò)數(shù)據(jù),或讀一個(gè)文件,只有等讀完這個(gè)數(shù)據(jù)或文件才能接收下一個(gè)消息。在執(zhí)行這個(gè)子函數(shù)過程中你什么也不能干。但往往讀網(wǎng)絡(luò)數(shù)據(jù)和等待用戶輸入有很多時(shí)間處于等待狀態(tài),多線程利用這個(gè)特點(diǎn)將任務(wù)分成多個(gè)并發(fā)任務(wù)后,就可以解決這個(gè)問題。Java中的線程類
1.擴(kuò)展java.lang.Thread類,用它覆蓋Thread類的run方法。
2.生成實(shí)現(xiàn)java.lang.Runnable接口的類并將其它的實(shí)例與java.lang.Thread實(shí)例相關(guān)聯(lián)。
Thread類是負(fù)責(zé)向其它類提供線程支持的最主要的類,要使用一個(gè)類具有線程功能,在Java中只要簡單地從Thread類派生一個(gè)子類就可以了擴(kuò)展Thread類,如.java。
Thread類最重要的方法是run方法。run方法是新線程執(zhí)行的方法,因此生成java.lang.Thread的子類時(shí),必須有相應(yīng)的run方法。
//.java
public class extends Thread//繼承Tread類
private int count=0
//定義一個(gè)count變量用于統(tǒng)計(jì)打印的次數(shù)并共享變量
public static void args//main方法開始
p=new //創(chuàng)建一個(gè)線程實(shí)例
p.start//執(zhí)行線程
for{;;}//主線程main方法執(zhí)行一個(gè)循環(huán),for執(zhí)行一個(gè)死循環(huán)count++
System.out.+″:Mainn″//主線程中打印count
+“main”變量的值,并換行
public void run//線程類必須有的run()方法for{;;}count++
System.out.+″:Threadn″
上面這段程序便是繼承java.lang.Tread并覆蓋run的方法。用Java
虛擬機(jī)啟動程序時(shí),這個(gè)程序會先生成一個(gè)線程并調(diào)用程序主類的main方法。這個(gè)程序中的main方法生成新線程,連接打印“Thread”。在啟動線程之后,主線程繼續(xù)打印“Main”。
編譯并執(zhí)行這個(gè)程序,然后立即按“Ctrl+C”鍵中斷程序,你會看到上面所述的兩個(gè)線程不斷打印出:XXX:main…..XXX:Thread….
XXX代表的是數(shù)字,也就是上面count的值。在筆者的機(jī)器上,不同時(shí)刻這兩個(gè)線程打印的次數(shù)不一樣,先打印20個(gè)main(也就是先執(zhí)行20次主線程)再打印出50次Thread,然后再打印main……
提示:為了便于查看該程序的執(zhí)行結(jié)果,你可以將執(zhí)行結(jié)果導(dǎo)入一個(gè)文本文件,然后打開這個(gè)文件查看各線程執(zhí)行的情況。如運(yùn)行:
javac .java
Java .txt
*個(gè)命令javac
.java是編譯java程序,第二個(gè)是執(zhí)行該程序并將結(jié)果導(dǎo)入1.txt文件。當(dāng)然你可以直接執(zhí)行命令:java
java Socket編程實(shí)現(xiàn)的最簡單的多線程Web服務(wù)器
import java.io.;
import java.net.;
import java.net.Socket;
public class Test {
public static void main(String[] args) throws Exception {
server = new (888);
while(true) {
Socket s = server.accept();
Processer p = new Processer(s);
Thread t = new Thread(p);
t.start();
}
}
}
class Processer Runnable {
private Socket socket;
public Processer(Socket s) {
// TODO Auto-generated stub
this.socket = s;
}
@Override
public void run() {
try {
out=new (socket.(),true);
out.println("HTTP/1.0 200 OK");
out.println("Content-Type:text/html;charset=utf-8");
out.println();
out.println("<h1> Web服務(wù)器測試成功!</h1>");
out.close();
} catch(Exception ex) {
ex.();
} finally {
try {
socket.close();
} catch (Exception e) {
e.();
}
}
}
}
能不能簡單描述一下你在java web開發(fā)中需要用到多線程編程的場景?
最典型的應(yīng)用比如tomcat,tomcat內(nèi)部采用的就是多線程,上百個(gè)客戶端訪問同一個(gè)web應(yīng)用,tomcat接入后都是把后續(xù)的處理扔給一個(gè)新的線程來處理,這個(gè)新的線程*調(diào)用到我們的servlet程序,比如doGet或者doPost方法。
如果不采用多線程機(jī)制,上百個(gè)人同時(shí)訪問一個(gè)web應(yīng)用的時(shí)候,tomcat就得排隊(duì)串行處理了,那樣客戶端根本是無法忍受那種訪問速度的。
還有就是需要異步處理的時(shí)候,需要使用多線程。比如task a和task b要并行處理,單個(gè)線程只能串行處理,先做完task a然后再做task b。如果想要多個(gè)task同時(shí)執(zhí)行的話,就必須為每個(gè)task分配一個(gè)線程,然后通過java虛擬機(jī)的線程調(diào)度,來同時(shí)執(zhí)行多個(gè)任務(wù)。比如你的CPU是多核心的話,就可以讓一個(gè)CPU執(zhí)行一個(gè)線程。如果只有一個(gè)CPU的話,底層是按照分時(shí)復(fù)用的原則,各個(gè)線程按照時(shí)間片來獲得CPU資源。