1. 程式人生 > >【java多執行緒】多執行緒的建立三種方式--筆記

【java多執行緒】多執行緒的建立三種方式--筆記

申明:執行緒的概念以及程序的相關概念,可以參考網路上其他資料,這裡只討論多執行緒是怎麼實現。

一、多執行緒的簡單理解

明白什麼是多執行緒,小生通俗一點的理解為:在一個程式裡,我想同時讓這個程式完成多個任務。

比如:讓主函式 main 在列印1~100之間的所有整數的時候,要求在主函式列印到 20 的時候,再執行另一個類裡的程式,讓它列印10~100之間的所有整數。

這裡忽略同程序內的多執行緒之間的搶佔時間問題,上面的舉例需求是要求一個程式只要有發生同時執行倆個程式的情況就行,即不準出現無論程式跑多少次都是先把 main 函式的1~100 的所有整數列印完再列印10~100 之間的所有整數(PS:如果是這樣的話,那就是 main 呼叫其他類的方法,屬於單執行緒了)。

二、建立多執行緒的三種方式(小生寫的比較繁綴羅嗦,建議閱讀完之後,參考程式碼再閱讀一次。)

第一種方式:

建立:編寫一個類 MyThread1 (這裡只是小生的自定義命名,方便與程式碼里名稱一致)讓它繼承 Thread 類,

並把需要多執行緒執行的程式放到 public void run() 方法裡。

啟動:在主函式中,new 出 MyThread1 類的例項。

執行:呼叫 MyThread1 類的例項的 start() 方法即可。

第二種方式:

建立:編寫一個類 MyThread2 讓它實現 Runnable 介面,並且要重寫 run() 方法(把需要多執行緒執行的程式放到 public void run() 方法裡)。

啟動:在主函式中,new 出 MyThread1 類的例項,

new 出Thread 類(帶有 target 的構造方法),

把MyThread1 類的例項作為引數傳入Thread 類的構造方法裡。

執行:呼叫 Thread 類的例項的 start() 方法即可。

第三種方式:

建立:實現 Callable 介面(小生定義這個類為 MyCallable),並且實現 call() 方法,注意 call() 方法是有返回值的。

啟動:new 出Callable 介面的實現類MyCallable,

new 出 FutureTask 類的例項 task,

把call() 方法的返回值放入FutureTask 類的構造方法裡,

把 task 放入 new 出的 Thread 構造方法裡。

執行:呼叫 Thread 類的例項的 start() 方法即可。

三種方式的利弊總結:

  第一種方法好處:建立已經繼承 Thread 類的類的例項,呼叫 start() 方法就能執行,程式碼寫起來很方便,

    當然缺點就是繼承了Thread 父類,就沒有辦法繼承其他的類了,擴充套件性不好。所以一般不建議用這種方式建立多執行緒。

  第二種方法好處:繼承介面,擴充套件性好。

    弊端是相對的,第一種方式不好也是相對於第二種來說的,而第二種方式相比第三種方式來說,run() 方法沒有返回值,並且不能申明丟擲異常。

  第三種方式好處上面已經說明,不好的就是編碼很麻煩(小生太笨看了半天才搞明白)

四、建立多執行緒的三種方式的程式碼演示

說明:小生會對每種方式的每條執行緒進行重新命名,只是為了方便程式碼執行效果演示。

java 預設執行緒的名稱規則:java 中的 main 函式本身就是一個預設的主執行緒,名字為:main(在下面例子可以證實 main 執行緒在 jvm 中的預設名稱)

如果自己定義的執行緒沒有定義名稱,則系統預設按照 Thread-0,Thread-1,……的命名方式進行命名。也可以通過對執行緒的構造方法進行重新命名。

4.1 繼承 Thread 類

  偷窺一下 API 發現 Thread 類實現了 Runnable 介面,currentThread() 靜態方法返回當前執行緒這個例項,再 getName() 一下就得到當前執行緒的名字了。

       

   

  

  MyThread1 執行緒:

package com.test.threadDemo1;

public class MyThread1 extends Thread {
    
    public MyThread1(String name) {
        this.setName(name);
    }

    public void run() {
        for(int i=20;i<=100;i++) {
            System.out.println(getName()+"..."+i);
        }
    }
}

  main 執行緒:

package com.test.threadDemo1;
/**
 * 多執行緒的實現之一:繼承 Thread 類
 * @author Administrator
 *
 */
public class ThreadDemo1 {
    public static void main(String[] args) {
        for (int i=1;i<=100;i++) {
            System.out.println(Thread.currentThread().getName()+"..."+i);
            
            if(i==30) {
                MyThread1 myThread = new MyThread1("新執行緒");
                myThread.start();
            }
        }
    }
}

  執行結果:(有交叉執行的情況發生,就是多執行緒了)

  從結果可以看出,當 main 執行緒跑到 30 的時候還在“搶佔” CPU

  

4.2 實現 Runable 介面

  MyThread 執行緒:

package com.test.threadDemo1;

public class MyThread2 implements Runnable {
    
    public MyThread2(String name) {
        Thread.currentThread().setName(name);
    }
    
    @Override
    public void run() {
        for(int i=20;i<=100;i++) {
            System.out.println(Thread.currentThread().getName()+"..."+i);
        }
    }
    
}

  main 執行緒:

package com.test.threadDemo1;
/**
 * 多執行緒的實現之二:實現 Runable 介面
 * @author Administrator
 *
 */
public class ThreadDemo2 {
    public static void main(String[] args) {
        for (int i=1;i<=100;i++) {
            System.out.println(Thread.currentThread().getName()+"..."+i);
            
            if(i==30) {
                MyThread2 myThread = new MyThread2("新執行緒");
                
                Thread thread = new Thread(myThread);
                
                thread.start();
            }
        }
    }
}

  執行結果:

  

4.3 實現 Callable 介面和 Future 介面

  Future介面的實現類是 FutureTask,它實現了 Runable 介面,所以能夠作為 target 引數傳到 Thread 類的構造方法裡。

  從構造方法裡可以看出 FutureTask 的構造方法裡傳入 callable 的實現類就行了。

  MyThread3 執行緒:

package com.test.threadDemo1;

import java.util.concurrent.Callable;

public class MyThread3 implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        int i = 20;
        for(;i<=100;i++) {
            System.out.println(Thread.currentThread().getName()+"..."+i);
        }
        return i;
    }

}

  main 執行緒:

package com.test.threadDemo1;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

/**
 * 多執行緒的實現之三:實現 Callable 介面和 Future 介面
 * @author Administrator
 *
 */
public class ThreadDemo3 {
    public static void main(String[] args) {
        
        Callable<Integer> myThread3 = new MyThread3();        
        FutureTask<Integer> task = new FutureTask<Integer>(myThread3);
        
        for (int i=1;i<=100;i++) {
            System.out.println(Thread.currentThread().getName()+"..."+i);
            
            if(i==30) {
                                
                Thread thread = new Thread(task,"新執行緒");
                thread.start();
            }
        }
    }
}

  執行結果: