當前位置:首頁 » 編程語言 » java多線程實現方式

java多線程實現方式

發布時間: 2023-05-24 12:24:00

A. 在java 中多線程的實現方法有哪些,如何使用

Java多線程的創建及啟動

Java中線程的創建常見有如三種基本形式

1.繼承Thread類,重寫該類的run()方法。

復制代碼

1 class MyThread extends Thread {

2

3 private int i = 0;

4

5 @Override

6 public void run() {

7 for (i = 0; i < 100; i++) {

8 System.out.println(Thread.currentThread().getName() + " " + i);

9 }

10 }

11 }

復制代碼

復制代碼

1 public class ThreadTest {

2

3 public static void main(String[] args) {

4 for (int i = 0; i < 100; i++) {

5 System.out.println(Thread.currentThread().getName() + " " + i);

6 if (i == 30) {

7 Thread myThread1 = new MyThread(); // 創建一個新的線程 myThread1 此線程進入新建狀態

8 Thread myThread2 = new MyThread(); // 創建一個新的線程 myThread2 此線程進入新建狀態

9 myThread1.start(); // 調用start()方法使得線程進入就緒狀態

10 myThread2.start(); // 調用start()方法使得線程進入就緒狀態

11 }

12 }

13 }

14 }

復制代碼

如上所示,繼承Thread類,通過重寫run()方法定義了一個新的線程類MyThread,其中run()方法的方法體代表了線程需要完成的任務,稱之為線程執行體。當創建此線程類對象時一個新的線程得以創建,並進入到線程新建狀態。通過調用線程對象引用的start()方法,使得該線程進入到就緒狀態,此時此線程並不一定會馬上得以執行,這取決於CPU調度時機。

2.實現Runnable介面,並重寫該介面的run()方法,該run()方法同樣是線程執行體,創建Runnable實現類的實例,並以此實例作為Thread類的target來創建Thread對象,該Thread對象才是真正的線程對象。

復制代碼

1 class MyRunnable implements Runnable {

2 private int i = 0;

3

4 @Override

5 public void run() {

6 for (i = 0; i < 100; i++) {

7 System.out.println(Thread.currentThread().getName() + " " + i);

8 }

9 }

10 }

復制代碼

復制代碼

1 public class ThreadTest {

2

3 public static void main(String[] args) {

4 for (int i = 0; i < 100; i++) {

5 System.out.println(Thread.currentThread().getName() + " " + i);

6 if (i == 30) {

7 Runnable myRunnable = new MyRunnable(); // 創建一個Runnable實現類的對象

8 Thread thread1 = new Thread(myRunnable); // 將myRunnable作為Thread target創建新的線程

9 Thread thread2 = new Thread(myRunnable);

10 thread1.start(); // 調用start()方法使得線程進入就緒狀態

11 thread2.start();

12 }

13 }

14 }

15 }

復制代碼

相信以上兩種創建新線程的方式大家都很熟悉了,那麼Thread和Runnable之間到底是什麼關系呢?我們首先來看一下下面這個例子。

復制代碼

1 public class ThreadTest {

2

3 public static void main(String[] args) {

4 for (int i = 0; i < 100; i++) {

5 System.out.println(Thread.currentThread().getName() + " " + i);

6 if (i == 30) {

7 Runnable myRunnable = new MyRunnable();

8 Thread thread = new MyThread(myRunnable);

9 thread.start();

10 }

11 }

12 }

13 }

14

15 class MyRunnable implements Runnable {

16 private int i = 0;

17

18 @Override

19 public void run() {

20 System.out.println("in MyRunnable run");

21 for (i = 0; i < 100; i++) {

22 System.out.println(Thread.currentThread().getName() + " " + i);

23 }

24 }

25 }

26

27 class MyThread extends Thread {

28

29 private int i = 0;

30

31 public MyThread(Runnable runnable){

32 super(runnable);

33 }

34

35 @Override

36 public void run() {

37 System.out.println("in MyThread run");

38 for (i = 0; i < 100; i++) {

39 System.out.println(Thread.currentThread().getName() + " " + i);

40 }

41 }

42 }

復制代碼

同樣的,與實現Runnable介面創建線程方式相似,不同的地方在於

1 Thread thread = new MyThread(myRunnable);

那麼這種方式可以順利創建出一個新的線程么?答案是肯定的。至於此時的線程執行體到底是MyRunnable介面中的run()方法還是MyThread類中的run()方法呢?通過輸出我們知道線程執行體是MyThread類中的run()方法。其實原因很簡單,因為Thread類本身也是實現了Runnable介面,而run()方法最先是在Runnable介面中定義的方法。

1 public interface Runnable {

2

3 public abstract void run();

4

5 }

我們看一下Thread類中對Runnable介面中run()方法的實現:

復制代碼

@Override

public void run() {

if (target != null) {

target.run();

}

}

復制代碼

也就是說,當執行到Thread類中的run()方法時,會首先判斷target是否存在,存在則執行target中的run()方法,也就是實現了Runnable介面並重寫了run()方法的類中的run()方法。但是上述給到的列子中,由於多態的存在,根本就沒有執行到Thread類中的run()方法,而是直接先執行了運行時類型即MyThread類中的run()方法。

3.使用Callable和Future介面創建線程。具體是創建Callable介面的實現類,並實現clall()方法。並使用FutureTask類來包裝Callable實現類的對象,且以此FutureTask對象作為Thread對象的target來創建線程。

看著好像有點復雜,直接來看一個例子就清晰了。

復制代碼

1 public class ThreadTest {

2

3 public static void main(String[] args) {

4

5 Callable<Integer> myCallable = new MyCallable(); // 創建MyCallable對象

6 FutureTask<Integer> ft = new FutureTask<Integer>(myCallable); //使用FutureTask來包裝MyCallable對象

7

8 for (int i = 0; i < 100; i++) {

9 System.out.println(Thread.currentThread().getName() + " " + i);

10 if (i == 30) {

11 Thread thread = new Thread(ft); //FutureTask對象作為Thread對象的target創建新的線程

12 thread.start(); //線程進入到就緒狀態

13 }

14 }

15

16 System.out.println("主線程for循環執行完畢..");

17

18 try {

19 int sum = ft.get(); //取得新創建的新線程中的call()方法返回的結果

20 System.out.println("sum = " + sum);

21 } catch (InterruptedException e) {

22 e.printStackTrace();

23 } catch (ExecutionException e) {

24 e.printStackTrace();

25 }

26

27 }

28 }

29

30

31 class MyCallable implements Callable<Integer> {

32 private int i = 0;

33

34 // 與run()方法不同的是,call()方法具有返回值

35 @Override

36 public Integer call() {

37 int sum = 0;

38 for (; i < 100; i++) {

39 System.out.println(Thread.currentThread().getName() + " " + i);

40 sum += i;

41 }

42 return sum;

43 }

44

45 }

復制代碼

首先,我們發現,在實現Callable介面中,此時不再是run()方法了,而是call()方法,此call()方法作為線程執行體,同時還具有返回值!在創建新的線程時,是通過FutureTask來包裝MyCallable對象,同時作為了Thread對象的target。那麼看下FutureTask類的定義:

1 public class FutureTask<V> implements RunnableFuture<V> {

2

3 //....

4

5 }

1 public interface RunnableFuture<V> extends Runnable, Future<V> {

2

3 void run();

4

5 }

於是,我們發現FutureTask類實際上是同時實現了Runnable和Future介面,由此才使得其具有Future和Runnable雙重特性。通過Runnable特性,可以作為Thread對象的target,而Future特性,使得其可以取得新創建線程中的call()方法的返回值。

執行下此程序,我們發現sum = 4950永遠都是最後輸出的。而「主線程for循環執行完畢..」則很可能是在子線程循環中間輸出。由CPU的線程調度機制,我們知道,「主線程for循環執行完畢..」的輸出時機是沒有任何問題的,那麼為什麼sum =4950會永遠最後輸出呢?

原因在於通過ft.get()方法獲取子線程call()方法的返回值時,當子線程此方法還未執行完畢,ft.get()方法會一直阻塞,直到call()方法執行完畢才能取到返回值。

上述主要講解了三種常見的線程創建方式,對於線程的啟動而言,都是調用線程對象的start()方法,需要特別注意的是:不能對同一線程對象兩次調用start()方法。

你好,本題已解答,如果滿意

請點右下角「採納答案」。


B. 在Java 中多線程的實現方法有哪些,如何使用

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。

C. java多線程有幾種實現方法線程之間如何同步

一、為什麼要線程同步

因為當我們有多個線程要同時訪問一個變數或對象時,如果這些線程中既有讀又有寫操作時,就會導致變數值或對象的狀態出現混亂,從而導致程序異常。舉個例子,如果一個銀行賬戶同時被兩個線程操作,一個取100塊,一個存錢100塊。假設賬戶原本有0塊,如果取錢線程和存錢線程同時發生,會出現什麼結果呢?取錢不成功,賬戶余額是100.取錢成功了,賬戶余額是0.那到底是哪個呢?很難說清楚。因此多線程同步就是要解決這個問題。

二、不同步時的代碼

Bank.Java

packagethreadTest;

/**
*@authorww
*
*/
publicclassBank{

privateintcount=0;//賬戶余額

//存錢
publicvoidaddMoney(intmoney){
count+=money;
System.out.println(System.currentTimeMillis()+"存進:"+money);
}

//取錢
publicvoidsubMoney(intmoney){
if(count-money<0){
System.out.println("余額不足");
return;
}
count-=money;
System.out.println(+System.currentTimeMillis()+"取出:"+money);
}

//查詢
publicvoidlookMoney(){
System.out.println("賬戶余額:"+count);
}
}

SyncThreadTest.java


packagethreadTest;


publicclassSyncThreadTest{

publicstaticvoidmain(Stringargs[]){
finalBankbank=newBank();

Threadtadd=newThread(newRunnable(){

@Override
publicvoidrun(){
//TODOAuto-generatedmethodstub
while(true){
try{
Thread.sleep(1000);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
bank.addMoney(100);
bank.lookMoney();
System.out.println(" ");

}
}
});

Threadtsub=newThread(newRunnable(){

@Override
publicvoidrun(){
//TODOAuto-generatedmethodstub
while(true){
bank.subMoney(100);
bank.lookMoney();
System.out.println(" ");
try{
Thread.sleep(1000);
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
}
}
});
tsub.start();

tadd.start();
}



}

余額不足
賬戶余額:0


余額不足
賬戶余額:100


1441790503354存進:100
賬戶余額:100


1441790504354存進:100
賬戶余額:100


1441790504354取出:100
賬戶余額:100


1441790505355存進:100
賬戶余額:100


1441790505355取出:100
賬戶余額:100

三、使用同步時的代碼

(1)同步方法:


即有synchronized關鍵字修飾的方法。由於java的每個對象都有一個內置鎖,當用此關鍵字修飾方法時,內置鎖會保護整個方法。在調用該方法前,需要獲得內置鎖,否則就處於阻塞狀態。

修改後的Bank.java


packagethreadTest;

/**
*@authorww
*
*/
publicclassBank{

privateintcount=0;//賬戶余額

//存錢
(intmoney){
count+=money;
System.out.println(System.currentTimeMillis()+"存進:"+money);
}

//取錢
(intmoney){
if(count-money<0){
System.out.println("余額不足");
return;
}
count-=money;
System.out.println(+System.currentTimeMillis()+"取出:"+money);
}

//查詢
publicvoidlookMoney(){
System.out.println("賬戶余額:"+count);
}
}

再看看運行結果:


余額不足
賬戶余額:0


余額不足
賬戶余額:0


1441790837380存進:100
賬戶余額:100


1441790838380取出:100
賬戶余額:0
1441790838380存進:100
賬戶余額:100
1441790839381取出:100
賬戶余額:0

瞬間感覺可以理解了吧。


註: synchronized關鍵字也可以修飾靜態方法,此時如果調用該靜態方法,將會鎖住整個類

(2)同步代碼塊

即有synchronized關鍵字修飾的語句塊。被該關鍵字修飾的語句塊會自動被加上內置鎖,從而實現同步

Bank.java代碼如下:


packagethreadTest;

/**
*@authorww
*
*/
publicclassBank{

privateintcount=0;//賬戶余額

//存錢
publicvoidaddMoney(intmoney){

synchronized(this){
count+=money;
}
System.out.println(System.currentTimeMillis()+"存進:"+money);
}

//取錢
publicvoidsubMoney(intmoney){

synchronized(this){
if(count-money<0){
System.out.println("余額不足");
return;
}
count-=money;
}
System.out.println(+System.currentTimeMillis()+"取出:"+money);
}

//查詢
publicvoidlookMoney(){
System.out.println("賬戶余額:"+count);
}
}

運行結果如下:

余額不足
賬戶余額:0


1441791806699存進:100
賬戶余額:100


1441791806700取出:100
賬戶余額:0


1441791807699存進:100
賬戶余額:100

效果和方法一差不多。

註:同步是一種高開銷的操作,因此應該盡量減少同步的內容。通常沒有必要同步整個方法,使用synchronized代碼塊同步關鍵代碼即可。

(3)使用特殊域變數(volatile)實現線程同步


a.volatile關鍵字為域變數的訪問提供了一種免鎖機制
b.使用volatile修飾域相當於告訴虛擬機該域可能會被其他線程更新
c.因此每次使用該域就要重新計算,而不是使用寄存器中的值
d.volatile不會提供任何原子操作,它也不能用來修飾final類型的變數

Bank.java代碼如下:


packagethreadTest;

/**
*@authorww
*
*/
publicclassBank{

privatevolatileintcount=0;//賬戶余額

//存錢
publicvoidaddMoney(intmoney){

count+=money;
System.out.println(System.currentTimeMillis()+"存進:"+money);
}

//取錢
publicvoidsubMoney(intmoney){

if(count-money<0){
System.out.println("余額不足");
return;
}
count-=money;
System.out.println(+System.currentTimeMillis()+"取出:"+money);
}

//查詢
publicvoidlookMoney(){
System.out.println("賬戶余額:"+count);
}
}

運行效果怎樣呢?


余額不足
賬戶余額:0


余額不足
賬戶余額:100


1441792010959存進:100
賬戶余額:100


1441792011960取出:100
賬戶余額:0


1441792011961存進:100
賬戶余額:100

是不是又看不懂了,又亂了。這是為什麼呢?就是因為volatile不能保證原子操作導致的,因此volatile不能代替synchronized。此外volatile會組織編譯器對代碼優化,因此能不使用它就不適用它吧。它的原理是每次要線程要訪問volatile修飾的變數時都是從內存中讀取,而不是存緩存當中讀取,因此每個線程訪問到的變數值都是一樣的。這樣就保證了同步。


(4)使用重入鎖實現線程同步

在JavaSE5.0中新增了一個java.util.concurrent包來支持同步。ReentrantLock類是可重入、互斥、實現了Lock介面的鎖,它與使用synchronized方法和快具有相同的基本行為和語義,並且擴展了其能力。
ReenreantLock類的常用方法有:
ReentrantLock() : 創建一個ReentrantLock實例
lock() : 獲得鎖
unlock() : 釋放鎖
註:ReentrantLock()還有一個可以創建公平鎖的構造方法,但由於能大幅度降低程序運行效率,不推薦使用
Bank.java代碼修改如下:


packagethreadTest;

importjava.util.concurrent.locks.Lock;
importjava.util.concurrent.locks.ReentrantLock;

/**
*@authorww
*
*/
publicclassBank{

privateintcount=0;//賬戶余額

//需要聲明這個鎖
privateLocklock=newReentrantLock();

//存錢
publicvoidaddMoney(intmoney){
lock.lock();//上鎖
try{
count+=money;
System.out.println(System.currentTimeMillis()+"存進:"+money);

}finally{
lock.unlock();//解鎖
}
}

//取錢
publicvoidsubMoney(intmoney){
lock.lock();
try{

if(count-money<0){
System.out.println("余額不足");
return;
}
count-=money;
System.out.println(+System.currentTimeMillis()+"取出:"+money);
}finally{
lock.unlock();
}
}

//查詢
publicvoidlookMoney(){
System.out.println("賬戶余額:"+count);
}
}

運行效果怎麼樣呢?


余額不足
賬戶余額:0


余額不足
賬戶余額:0


1441792891934存進:100
賬戶余額:100


1441792892935存進:100
賬戶余額:200


1441792892954取出:100
賬戶余額:100

效果和前兩種方法差不多。


如果synchronized關鍵字能滿足用戶的需求,就用synchronized,因為它能簡化代碼 。如果需要更高級的功能,就用ReentrantLock類,此時要注意及時釋放鎖,否則會出現死鎖,通常在finally代碼釋放鎖

(5)使用局部變數實現線程同步


Bank.java代碼如下:


packagethreadTest;


/**
*@authorww
*
*/
publicclassBank{

privatestaticThreadLocal<Integer>count=newThreadLocal<Integer>(){

@Override
protectedIntegerinitialValue(){
//TODOAuto-generatedmethodstub
return0;
}

};


//存錢
publicvoidaddMoney(intmoney){
count.set(count.get()+money);
System.out.println(System.currentTimeMillis()+"存進:"+money);

}

//取錢
publicvoidsubMoney(intmoney){
if(count.get()-money<0){
System.out.println("余額不足");
return;
}
count.set(count.get()-money);
System.out.println(+System.currentTimeMillis()+"取出:"+money);
}

//查詢
publicvoidlookMoney(){
System.out.println("賬戶余額:"+count.get());
}
}

運行效果:


余額不足
賬戶余額:0


余額不足
賬戶余額:0


1441794247939存進:100
賬戶余額:100


余額不足
1441794248940存進:100
賬戶余額:0


賬戶余額:200


余額不足
賬戶余額:0


1441794249941存進:100
賬戶余額:300

看了運行效果,一開始一頭霧水,怎麼只讓存,不讓取啊?看看ThreadLocal的原理:


如果使用ThreadLocal管理變數,則每一個使用該變數的線程都獲得該變數的副本,副本之間相互獨立,這樣每一個線程都可以隨意修改自己的變數副本,而不會對其他線程產生影響。現在明白了吧,原來每個線程運行的都是一個副本,也就是說存錢和取錢是兩個賬戶,知識名字相同而已。所以就會發生上面的效果。


ThreadLocal與同步機制
a.ThreadLocal與同步機制都是為了解決多線程中相同變數的訪問沖突問題

b.前者採用以"空間換時間"的方法,後者採用以"時間換空間"的方式

D. java多線程都有幾種方式實現

有三種:
(1)繼承Thread類,重寫run函數
創建:
class xx extends Thread{
public void run(){
Thread.sleep(1000) //線程休眠1000毫秒,sleep使線程進入Block狀態,並釋放資源
}}
開啟線程:
對象.start() //啟動線程,run函數運行
(2)實現Runnable介面,重寫run函數
開啟線程:
Thread t = new Thread(對象) //創建線程對象
t.start()
(3)實現Callable介面,重寫call函數
Callable是類似於Runnable的介面,實現Callable介面的類和實現Runnable的類都是可被其它線程執行的任務。
Callable和Runnable有幾點不同:
①Callable規定的方法是call(),而Runnable規定的方法是run().
②Callable的任務執行後可返回值,而Runnable的任務是不能返回值的
③call()方法可拋出異常,而run()方法是不能拋出異常的。
④運行Callable任務可拿到一個Future對象,Future表示非同步計算的結果。它提供了檢查計算是否完成的方法,以等
待計算的完成,並檢索計算的結果.通過Future對象可了解任務執行情況,可取消任務的執行,還可獲取任務執行的結果

E. 什麼是JAVA的多線程

簡單,先回答什麼是線程:即程序的執行路徑,再回答多線程:多線程就是一個程序中有多條不同的執行路徑

JAVA多線程的優點:可以並發的執行多項任務,比如說你瀏覽網頁的同時還可以聽歌

F. JAVA多線程有哪幾種實現方式

JAVA多線程實現方式主要有三種:繼承Thread類、實現Runnable介面、使用ExecutorService、Callable、Future實現有返回結果的多線程。其中前兩種方式線程執行完後都沒有返回值,只有最後一種是帶返回值的。

1、繼承Thread類實現多線程
繼承Thread類的方法盡管被我列為一種多線程實現方式,但Thread本質上也是實現了Runnable介面的一個實例,它代表一個線程的實例,並且,啟動線程的唯一方法就是通過Thread類的start()實例方法。start()方法是一個native方法,它將啟動一個新線程,並執行run()方法。這種方式實現多線程很簡單,通過自己的類直接extend Thread,並復寫run()方法,就可以啟動新線程並執行自己定義的run()方法。例如:

[java]view plain

  • {

  • publicvoidrun(){

  • System.out.println("MyThread.run()");

  • }

  • }

  • 在合適的地方啟動線程如下:

  • [java]view plain

  • MyThreadmyThread1=newMyThread();

  • MyThreadmyThread2=newMyThread();

  • myThread1.start();

  • myThread2.start();


  • 2、實現Runnable介面方式實現多線程

  • 如果自己的類已經extends另一個類,就無法直接extends Thread,此時,必須實現一個Runnable介面,如下:

  • [java]view plain

  • {

  • publicvoidrun(){

  • System.out.println("MyThread.run()");

  • }

  • }

  • 為了啟動MyThread,需要首先實例化一個Thread,並傳入自己的MyThread實例:

  • [java]view plain

  • MyThreadmyThread=newMyThread();

  • Threadthread=newThread(myThread);

  • thread.start();

  • 事實上,當傳入一個Runnable target參數給Thread後,Thread的run()方法就會調用target.run(),參考JDK源代碼:

  • [java]view plain

  • publicvoidrun(){

  • if(target!=null){

  • target.run();

  • }

  • }


  • 3、使用ExecutorService、Callable、Future實現有返回結果的多線程

  • ExecutorService、Callable、Future這個對象實際上都是屬於Executor框架中的功能類。想要詳細了解Executor框架的可以訪問http://www.javaeye.com/topic/366591 ,這裡面對該框架做了很詳細的解釋。返回結果的線程是在JDK1.5中引入的新特徵,確實很實用,有了這種特徵我就不需要再為了得到返回值而大費周折了,而且即便實現了也可能漏洞百出。

  • 可返回值的任務必須實現Callable介面,類似的,無返回值的任務必須Runnable介面。執行Callable任務後,可以獲取一個Future的對象,在該對象上調用get就可以獲取到Callable任務返回的Object了,再結合線程池介面ExecutorService就可以實現傳說中有返回結果的多線程了。下面提供了一個完整的有返回結果的多線程測試例子,在JDK1.5下驗證過沒問題可以直接使用。
熱點內容
ct4哪個配置性價比最高 發布:2025-05-19 15:38:02 瀏覽:952
如何設置強緩存的失效時間 發布:2025-05-19 15:21:28 瀏覽:695
winxp無法訪問 發布:2025-05-19 15:19:48 瀏覽:947
文件預編譯 發布:2025-05-19 15:14:04 瀏覽:643
怎麼在伺服器上掛公網 發布:2025-05-19 15:14:02 瀏覽:272
濟南平安e通如何找回密碼 發布:2025-05-19 14:56:58 瀏覽:176
安卓手機如何找到iccid碼 發布:2025-05-19 14:46:51 瀏覽:227
編譯的內核為什麼那麼大 發布:2025-05-19 14:45:21 瀏覽:179
什麼控制壓縮 發布:2025-05-19 14:28:13 瀏覽:931
網路伺服器忙指什麼 發布:2025-05-19 14:28:10 瀏覽:189