1、繼承Thread類實現多線程
創新互聯服務項目包括漢南網站建設、漢南網站制作、漢南網頁制作以及漢南網絡營銷策劃等。多年來,我們專注于互聯網行業,利用自身積累的技術優勢、行業經驗、深度合作伙伴關系等,向廣大中小型企業、政府機構等提供互聯網行業的解決方案,漢南網站推廣取得了明顯的社會效益與經濟效益。目前,我們服務的客戶以成都為中心已經輻射到漢南省份的部分城市,未來相信會繼續擴大服務區域并繼續獲得客戶的支持與信任!
繼承Thread類的方法盡管被我列為一種多線程實現方式,但Thread本質上也是實現了Runnable接口的一個實例,它代表一個線程的實例,并且,啟動線程的唯一方法就是通過Thread類的start()實例方法。start()方法是一個native方法,它將啟動一個新線程,并執行run()方法。這種方式實現多線程很簡單,通過自己的類直接extend Thread,并復寫run()方法,就可以啟動新線程并執行自己定義的run()方法。例如:
[java] view plain copy
public class MyThread extends Thread {
public void run() {
System.out.println("MyThread.run()");
}
}
在合適的地方啟動線程如下:
[java] view plain copy
MyThread myThread1 = new MyThread();
MyThread myThread2 = new MyThread();
myThread1.start();
myThread2.start();
2、實現Runnable接口方式實現多線程
如果自己的類已經extends另一個類,就無法直接extends Thread,此時,必須實現一個Runnable接口,如下:
[java] view plain copy
public class MyThread extends OtherClass implements Runnable {
public void run() {
System.out.println("MyThread.run()");
}
}
為了啟動MyThread,需要首先實例化一個Thread,并傳入自己的MyThread實例:
[java] view plain copy
MyThread myThread = new MyThread();
Thread thread = new Thread(myThread);
thread.start();
事實上,當傳入一個Runnable target參數給Thread后,Thread的run()方法就會調用target.run(),參考JDK源代碼:
[java] view plain copy
public void run() {
if (target != null) {
target.run();
}
}
3、使用ExecutorService、Callable、Future實現有返回結果的多線程
ExecutorService、Callable、Future這個對象實際上都是屬于Executor框架中的功能類。想要詳細了解Executor框架的可以訪問 ,這里面對該框架做了很詳細的解釋。返回結果的線程是在JDK1.5中引入的新特征,確實很實用,有了這種特征我就不需要再為了得到返回值而大費周折了,而且即便實現了也可能漏洞百出。
可返回值的任務必須實現Callable接口,類似的,無返回值的任務必須Runnable接口。執行Callable任務后,可以獲取一個Future的對象,在該對象上調用get就可以獲取到Callable任務返回的Object了,再結合線程池接口ExecutorService就可以實現傳說中有返回結果的多線程了。下面提供了一個完整的有返回結果的多線程測試例子,在JDK1.5下驗證過沒問題可以直接使用。
在Java語言產生前 傳統的程序設計語言的程序同一時刻只能單任務操作 效率非常低 例如程序往往在接收數據輸入時發生阻塞 只有等到程序獲得數據后才能繼續運行 隨著Internet的迅猛發展 這種狀況越來越不能讓人們忍受 如果網絡接收數據阻塞 后臺程序就處于等待狀態而不繼續任何操作 而這種阻塞是經常會碰到的 此時CPU資源被白白的閑置起來 如果在后臺程序中能夠同時處理多個任務 該多好啊!應Internet技術而生的Java語言解決了這個問題 多線程程序是Java語言的一個很重要的特點 在一個Java程序中 我們可以同時并行運行多個相對獨立的線程 例如 我們如果創建一個線程來進行數據輸入輸出 而創建另一個線程在后臺進行其它的數據處理 如果輸入輸出線程在接收數據時阻塞 而處理數據的線程仍然在運行 多線程程序設計大大提高了程序執行效率和處理能力
線程的創建
我們知道Java是面向對象的程序語言 用Java進行程序設計就是設計和使用類 Java為我們提供了線程類Thread來創建線程 創建線程與創建普通的類的對象的操作是一樣的 而線程就是Thread類或其子類的實例對象 下面是一個創建啟動一個線程的語句
Thread thread =new Thread(); file://聲明一個對象實例 即創建一個線程
Thread run(); file://用Thread類中的run()方法啟動線程
從這個例子 我們可以通過Thread()構造方法創建一個線程 并啟動該線程 事實上 啟動線程 也就是啟動線程的run()方法 而Thread類中的run()方法沒有任何操作語句 所以這個線程沒有任何操作 要使線程實現預定功能 必須定義自己的run()方法 Java中通常有兩種方式定義run()方法
通過定義一個Thread類的子類 在該子類中重寫run()方法 Thread子類的實例對象就是一個線程 顯然 該線程有我們自己設計的線程體run()方法 啟動線程就啟動了子類中重寫的run()方法
通過Runnable接口 在該接口中定義run()方法的接口 所謂接口跟類非常類似 主要用來實現特殊功能 如復雜關系的多重繼承功能 在此 我們定義一個實現Runnable() 接口的類 在該類中定義自己的run()方法 然后以該類的實例對象為參數調用Thread類的構造方法來創建一個線程
線程被實際創建后處于待命狀態 激活(啟動)線程就是啟動線程的run()方法 這是通過調用線程的start()方法來實現的
下面一個例子實踐了如何通過上述兩種方法創建線程并啟動它們
// 通過Thread類的子類創建的線程 class thread extends Thread { file://自定義線程的run()方法 public void run() { System out println( Thread is running… ); } } file://通過Runnable接口創建的另外一個線程 class thread implements Runnable { file://自定義線程的run()方法 public void run() { System out println( Thread is running… ); } } file://程序的主類 class Multi_Thread file://聲明主類 { plubic static void mail(String args[]) file://聲明主方法 { thread threadone=new thread (); file://用Thread類的子類創建線程 Thread threado=new Thread(new thread ()); file://用Runnable接口類的對象創建線程 threadone start(); threado start(); 方法啟動線程 } }
運行該程序就可以看出 線程threadone和threado交替占用CPU 處于并行運行狀態 可以看出 啟動線程的run()方法是通過調用線程的start()方法來實現的(見上例中主類) 調用start()方法啟動線程的run()方法不同于一般的調用方法 調用一般方法時 必須等到一般方法執行完畢才能夠返回start()方法 而啟動線程的run()方法后 start()告訴系統該線程準備就緒可以啟動run()方法后 就返回start()方法執行調用start()方法語句下面的語句 這時run()方法可能還在運行 這樣 線程的啟動和運行并行進行 實現了多任務操作
線程的優先級
對于多線程程序 每個線程的重要程度是不盡相同 如多個線程在等待獲得CPU時間時 往往我們需要優先級高的線程優先搶占到CPU時間得以執行 又如多個線程交替執行時 優先級決定了級別高的線程得到CPU的次數多一些且時間多長一些 這樣 高優先級的線程處理的任務效率就高一些
Java中線程的優先級從低到高以整數 ~ 表示 共分為 級 設置優先級是通過調用線程對象的setPriority()方法 如上例中 設置優先級的語句為
thread threadone=new thread (); file://用Thread類的子類創建線程
Thread threado=new Thread(new thread ()); file://用Runnable接口類的對象創建線程
threadone setPriority( ); file://設置threadone的優先級
threado setPriority( ); file://設置threado的優先級
threadone start(); threado start(); 方法啟動線程
這樣 線程threadone將會優先于線程threado執行 并將占有更多的CPU時間 該例中 優先級設置放在線程啟動前 也可以在啟動后進行設置 以滿足不同的優先級需求
線程的(同步)控制
一個Java程序的多線程之間可以共享數據 當線程以異步方式訪問共享數據時 有時候是不安全的或者不和邏輯的 比如 同一時刻一個線程在讀取數據 另外一個線程在處理數據 當處理數據的線程沒有等到讀取數據的線程讀取完畢就去處理數據 必然得到錯誤的處理結果 這和我們前面提到的讀取數據和處理數據并行多任務并不矛盾 這兒指的是處理數據的線程不能處理當前還沒有讀取結束的數據 但是可以處理其它的數據
如果我們采用多線程同步控制機制 等到第一個線程讀取完數據 第二個線程才能處理該數據 就會避免錯誤 可見 線程同步是多線程編程的一個相當重要的技術
在講線程的同步控制前我們需要交代如下概念
用Java關鍵字synchonized同步對共享數據操作的方法
在一個對象中 用synchonized聲明的方法為同步方法 Java中有一個同步模型 監視器 負責管理線程對對象中的同步方法的訪問 它的原理是 賦予該對象唯一一把 鑰匙 當多個線程進入對象 只有取得該對象鑰匙的線程才可以訪問同步方法 其它線程在該對象中等待 直到該線程用wait()方法放棄這把鑰匙 其它等待的線程搶占該鑰匙 搶占到鑰匙的線程后才可得以執行 而沒有取得鑰匙的線程仍被阻塞在該對象中等待
file://聲明同步的一種方式 將方法聲明同步
class store {public synchonized void store_in(){… }public synchonized void store_out(){ … }}
利用wait() notify()及notifyAll()方法發送消息實現線程間的相互聯系
Java程序中多個線程通過消息來實現互動聯系的 這幾種方法實現了線程間的消息發送 例如定義一個對象的synchonized 方法 同一時刻只能夠有一個線程訪問該對象中的同步方法 其它線程被阻塞 通常可以用notify()或notifyAll()方法喚醒其它一個或所有線程 而使用wait()方法來使該線程處于阻塞狀態 等待其它的線程用notify()喚醒
一個實際的例子就是生產和銷售 生產單元將產品生產出來放在倉庫中 銷售單元則從倉庫中提走產品 在這個過程中 銷售單元必須在倉庫中有產品時才能提貨 如果倉庫中沒有產品 則銷售單元必須等待
程序中 假如我們定義一個倉庫類store 該類的實例對象就相當于倉庫 在store類中定義兩個成員方法 store_in() 用來模擬產品制造者往倉庫中添加產品 strore_out()方法則用來模擬銷售者從倉庫中取走產品 然后定義兩個線程類 customer類 其中的run()方法通過調用倉庫類中的store_out()從倉庫中取走產品 模擬銷售者 另外一個線程類producer中的run()方法通過調用倉庫類中的store_in()方法向倉庫添加產品 模擬產品制造者 在主類中創建并啟動線程 實現向倉庫中添加產品或取走產品
如果倉庫類中的store_in() 和store_out()方法不聲明同步 這就是個一般的多線程 我們知道 一個程序中的多線程是交替執行的 運行也是無序的 這樣 就可能存在這樣的問題
倉庫中沒有產品了 銷售者還在不斷光顧 而且還不停的在 取 產品 這在現實中是不可思義的 在程序中就表現為負值 如果將倉庫類中的stroe_in()和store_out()方法聲明同步 如上例所示 就控制了同一時刻只能有一個線程訪問倉庫對象中的同步方法 即一個生產類線程訪問被聲明為同步的store_in()方法時 其它線程將不能夠訪問對象中的store_out()同步方法 當然也不能訪問store_in()方法 必須等到該線程調用wait()方法放棄鑰匙 其它線程才有機會訪問同步方法
lishixinzhi/Article/program/Java/gj/201311/27301
public class RunThread implements Runnable{
String name;
Thread runner;
static boolean bool=true;
public RunThread(String threadName) {
name=threadName;
}
public void onStart()
{
runner = new Thread(this);
runner.setName(name);
runner.start();
}
public void run() {
String name=Thread.currentThread().getName();
System.out.println(name + " 線程運行開始!");
int index=0;
if(name.equals("小寫字母"))
index='a';
else if(name.equals("大寫字母"))
index='A';
while(!bool);
bool=false;
for(int i=index;i26+index;i++)
System.out.print((char)i+" ");
System.out.println();
bool=true;
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + " 線程運行結束!");
}
public static void main(String[] args) {
RunThread a=new RunThread("小寫字母");
RunThread b=new RunThread("大寫字母");
a.onStart();
b.onStart();
//System.out.println(" 線程運行開始!");
}
1、 認識Thread和Runnable
Java中實現多線程有兩種途徑:繼承Thread類或者實現Runnable接口。Runnable是接口,建議用接口的方式生成線程,因為接口可以實現多繼承,況且Runnable只有一個run方法,很適合繼承。在使用Thread的時候只需繼承Thread,并且new一個實例出來,調用start()方法即可以啟動一個線程。
Thread Test = new Thread();
Test.start();
在使用Runnable的時候需要先new一個實現Runnable的實例,之后啟動Thread即可。
Test impelements Runnable;
Test t = new Test();
Thread test = new Thread(t);
test.start();
總結:Thread和Runnable是實現java多線程的2種方式,runable是接口,thread是類,建議使用runable實現java多線程,不管如何,最終都需要通過thread.start()來使線程處于可運行狀態。
2、 認識Thread的start和run
1) start:
用start方法來啟動線程,真正實現了多線程運行,這時無需等待run方法體代碼執行完畢而直接繼續執行下面的代碼。通過調用Thread類的start()方法來啟動一個線程,這時此線程處于就緒(可運行)狀態,并沒有運行,一旦得到spu時間片,就開始執行run()方法,這里方法run()稱為線程體,它包含了要執行的這個線程的內容,Run方法運行結束,此線程隨即終止。
2) run:
run()方法只是類的一個普通方法而已,如果直接調用Run方法,程序中依然只有主線程這一個線程,其程序執行路徑還是只有一條,還是要順序執行,還是要等待run方法體執行完畢后才可繼續執行下面的代碼,這樣就沒有達到寫線程的目的。
總結:調用start方法方可啟動線程,而run方法只是thread的一個普通方法調用,還是在主線程里執行。
3、 線程狀態說明
線程狀態從大的方面來說,可歸結為:初始狀態、可運行狀態、不可運行狀態和消亡狀態,具體可細分為上圖所示7個狀態,說明如下:
1) 線程的實現有兩種方式,一是繼承Thread類,二是實現Runnable接口,但不管怎樣,當我們new了thread實例后,線程就進入了初始狀態;
2) 當該對象調用了start()方法,就進入可運行狀態;
3) 進入可運行狀態后,當該對象被操作系統選中,獲得CPU時間片就會進入運行狀態;
4) 進入運行狀態后case就比較多,大致有如下情形:
·run()方法或main()方法結束后,線程就進入終止狀態;
·當線程調用了自身的sleep()方法或其他線程的join()方法,就會進入阻塞狀態(該狀態既停止當前線程,但并不釋放所占有的資源)。當sleep()結束或join()結束后,該線程進入可運行狀態,繼續等待OS分配時間片;
·當線程剛進入可運行狀態(注意,還沒運行),發現將要調用的資源被鎖牢(synchroniza,lock),將會立即進入鎖池狀態,等待獲取鎖標記(這時的鎖池里也許已經有了其他線程在等待獲取鎖標記,這時它們處于隊列狀態,既先到先得),一旦線程獲得鎖標記后,就轉入可運行狀態,等待OS分配CPU時間片;
·當線程調用wait()方法后會進入等待隊列(進入這個狀態會釋放所占有的所有資源,與阻塞狀態不同),進入這個狀態后,是不能自動喚醒的,必須依靠其他線程調用notify()或notifyAll()方法才能被喚醒(由于notify()只是喚醒一個線程,但我們由不能確定具體喚醒的是哪一個線程,也許我們需要喚醒的線程不能夠被喚醒,因此在實際使用時,一般都用notifyAll()方法,喚醒有所線程),線程被喚醒后會進入鎖池,等待獲取鎖標記。
·當線程調用stop方法,即可使線程進入消亡狀態,但是由于stop方法是不安全的,不鼓勵使用,大家可以通過run方法里的條件變通實現線程的stop。
分享標題:java中實現多線程代碼 java實現多線程方法
當前地址:http://vcdvsql.cn/article20/ddccico.html
成都網站建設公司_創新互聯,為您提供Google、靜態網站、網站制作、搜索引擎優化、微信小程序、標簽優化
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯