一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java 線程對比(Thread,Runnable,Callable)實例詳解

Java 線程對比(Thread,Runnable,Callable)實例詳解

2020-07-17 11:50android_小路 Java教程

這篇文章主要介紹了Java 線程(Thread,Runnable,Callable)實例詳解的相關資料,這里對java 線程的三種方法進行了對比,需要的朋友可以參考下

Java 線程對比Thread,Runnable,Callable

java 使用 Thread 類代表線程,所有現場對象都必須是 Thread 類或者其子類的實例。每個線程的作用是完成一定的任務,實際上就是執行一段程序流。java 使用線程執行體來代表這段程序流。

1.繼承Thread 類創建線程

啟動多線程的步驟如下:

(1)定義Thread 類的子類,并重寫該類的run() 方法,該run() 方法的方法體就代表類線程需要完成的任務。因此把run() 方法稱為線程執行體。
(2)創建 Thread 子類的實例,即創建線程對象。
(3)調用線程的star()方法來啟動該線程。

相關代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
   * 繼承 thread 的內部類,以買票例子
   */
  public class FirstThread extends Thread{
    private int i;
    private int ticket = 10;
 
    @Override
    public void run() {
      for (;i<20;i++) {
        //當繼承thread 時,直接使用this 可以獲取當前的線程,getName() 獲取當前線程的名字
//        Log.d(TAG,getName()+" "+i);
 
        if(this.ticket>0){
          Log.e(TAG, getName() + ", 賣票:ticket=" + ticket--);
        }
      }
 
    }
  }
 
  private void starTicketThread(){
    Log.d(TAG,"starTicketThread, "+Thread.currentThread().getName());
 
    FirstThread thread1 = new FirstThread();
    FirstThread thread2 = new FirstThread();
    FirstThread thread3 = new FirstThread();
 
    thread1.start();
    thread2.start();
    thread3.start();
 
    //開啟3個線程進行買票,每個線程都賣了10張,總共就30張票
 
  }

運行結果:

Java 線程對比(Thread,Runnable,Callable)實例詳解

可以看到 3 個線程輸入的 票數變量不連續,注意:ticket 是 FirstThread 的實例屬性,而不是局部變量,但是因為程序每次創建線程對象都需要創建一個FirstThread 的對象,所有多個線程不共享該實例的屬性。

2.實現 Runnable 接口創建線程

注意:public class Thread implements Runnable

(1)定義 Runnable 接口的實現類,并重寫該接口的run()方法,該run() 方法的方法體同樣是該線程的線程執行體。
(2)創建 Runnable 實例類的實例,此實例作為 Thread 的 target 來創建Thread 對象,該Thread 對象才是真正的對象。

相關代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
   * 實現 runnable 接口,創建線程類
   */
  public class SecondThread implements Runnable{
 
    private int i;
    private int ticket = 100;
 
    @Override
    public void run() {
      for (;i<20;i++) {
        //如果線程類實現 runnable 接口
        //獲取當前的線程,只能用 Thread.currentThread() 獲取當前的線程名
        Log.d(TAG,Thread.currentThread().getName()+" "+i);
 
        if(this.ticket>0){
          Log.e(TAG, Thread.currentThread().getName() + ", 賣票:ticket=" + ticket--);
        }
      }
    }
  }
 
 
  private void starTicketThread2(){
    Log.d(TAG,"starTicketThread2, "+Thread.currentThread().getName());
 
    SecondThread secondThread = new SecondThread();
 
    //通過new Thread(target,name)創建新的線程
    new Thread(secondThread,"買票人1").start();
    new Thread(secondThread,"買票人2").start();
    new Thread(secondThread,"買票人3").start();
 
    //雖然是開啟了3個線程,但是一共只買了100張票
  }

運行結果:

Java 線程對比(Thread,Runnable,Callable)實例詳解

可以看到 3 個線程輸入的 票數變量是連續的,采用 Runnable 接口的方式創建多個線程可以共享線程類的實例的屬性。這是因為在這種方式下,程序所創建的Runnable 對象只是線程的 target ,而多個線程可以共享同一個 target,所以多個線程可以共享同一個線程類(實際上應該是該線程的target 類)的實例屬性。

3.使用 Callable 和Future 創建線程

從 java 5 開始,Java 提供了 Callable 接口,該接口是runnable 的增強版,Callable 提供類一個 call() 方法可以作為線程執行體,但是call() 方法的功能更強大。

(1) call() 方法可以有返回值
(2) call() 方法可以聲明拋出異常

因此我們完全可以提供一個callable 對象作為Thread的 target ,而該線程的執行體就是該callable 對象的call() 方法。同時 java 5 提供了 Future 接口 來代表Callable 接口里 call() 方法的返回值,并且提供了一個 futureTask 的實現類,該實現類實現類 future 接口,并實現了runnable 接口—可以作為Thread 類的target.

啟動步驟如下:

(1)創建callable接口的實現類,并實現call() 方法,該call() 方法將作為線程的執行體,且該call() 方法是有返回值的。
(2)創建 callable實現類的實例,使用 FutureTask 類來包裝Callable對象,該FutureTask 對象封裝 call() 方法的返回值。
(3)使用FutureTask 對象作為Thread對象的target創建并啟動新線程。
(4)調用FutureTask對象的get()方法來獲取子線程執行結束后的返回值。

相關代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
   * 使用callable 來實現線程類
   */
  public class ThirdThread implements Callable<Integer>{
 
    private int ticket = 20;
 
    @Override
    public Integer call(){
 
      for ( int i = 0;i<10;i++) {
        //獲取當前的線程,只能用 Thread.currentThread() 獲取當前的線程名
//        Log.d(TAG,Thread.currentThread().getName()+" "+i);
 
        if(this.ticket>0){
          Log.e(TAG, Thread.currentThread().getName() + ", 賣票:ticket=" + ticket--);
        }
      }
 
 
      return ticket;
    }
  }
 
  private void starCallableThread(){
    ThirdThread thirdThread = new ThirdThread();
    FutureTask<Integer> task = new FutureTask<Integer>(thirdThread);
 
    new Thread(task,"有返回值的線程").start();
 
    try {
      Integer integer = task.get();
      Log.d(TAG,"starCallableThread, 子線程的返回值="+integer);
 
    } catch (InterruptedException e) {
      e.printStackTrace();
    } catch (ExecutionException e) {
      e.printStackTrace();
    }
 
  }

運行結果:

Java 線程對比(Thread,Runnable,Callable)實例詳解

注意:Callable的call() 方法允許聲明拋出異常,并且允許帶有返回值。
程序最后調用FutureTask 對象的get()方法來返回Call()方法的返回值,導致主線程被阻塞,直到call()方法結束并返回為止。

4.三種方式的對比

采用繼承Thread 類的方式創建多線程

劣勢: 已經繼承Thread類不能再繼承其他父類。

優勢: 編寫簡單

采用繼承Runnable,Callable 接口的方式創建多線程

劣勢: 編程稍微有點復雜,如果需要訪問當前線程必須使用Thread.currentThread()

優勢:

(1)還可以繼承其他類
(2)多個線程可以共享一個target 對象,所以非常適合多個相同的線程來處理同一份資源的情況,從而將cpu,代碼和數據分開,形成清晰的模型,較好的體現類面向對象的思想。

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

原文鏈接:http://blog.csdn.net/android_freshman/article/details/53787011

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产高清小视频 | 久久受www免费人成_看片中文 | 色天天综合网色鬼综合 | 二次元美女扒开内裤露尿口 | 国产综合社区 | 粗暴hd另类另类 | 国产精品成人一区二区1 | 国产福利微拍精品一区二区 | sex5·性屋娱乐 | 免费的强动漫人物的 | 国产精品久久久久久五月尺 | 午夜在线观看免费完整直播网 | 青青草99久久精品国产综合 | 精品国产成a人在线观看 | 亚洲精品国产自在现线最新 | 人人揉揉香蕉 | 男人爱看的网站 | 日韩欧一级毛片在线播无遮挡 | 免费国产午夜高清在线视频 | 国产精品吹潮香蕉在线观看 | 国产成人在线播放视频 | 国产成人黄网在线免 | 奇米影视888四色首页 | 日本视频中文字幕 | 亚洲国产精品网站久久 | 欧美一级视频在线 | 好爽好深好猛好舒服视频上 | 841995论坛网站2022年 | 日本人成动漫网站在线观看 | 韩国男女做性全过程视频 | 精品国产mmd在线观看 | 天天操丝袜 | 99精品视频免费观看 | 亚洲国产成人久久综合一区 | 国内精品露脸在线视频播放 | 色综合天天五月色 | 我年轻漂亮的继坶2中字在线播放 | 四虎影音先锋 | 99视频免费 | ysl千人千色t9t9t9 | 精精国产www视频在线观看免费 |