1. 程式人生 > 其它 >Java建立執行緒的三種方式

Java建立執行緒的三種方式

技術標籤:併發java

Java建立執行緒的三種方式

一、直接使用Thread建立(繼承Thread類)

這種方式通過直接覆蓋Thread類中的run方法建立執行緒

  • 繼承Thread類
  1. 首先建立一個類,繼承自Thread類
  2. 然後重寫Thread的run方法,方法裡面寫要併發執行的程式碼
  3. 在main方法裡面建立執行緒,使用start方法開啟執行緒。(注意:一定要使用start而不是run方法開啟執行緒。如果直接呼叫run()方法,程式將執行完run()方法後才會執行main()方法中後面的程式碼,這樣就是單執行緒執行而不是多執行緒併發執行了)
//繼承Thread類
class MyThread
extends Thread{ //重寫run方法 public void run() { //t1執行緒 System.out.println(Thread.currentThread().getName() + " is running"); } } public class Test1 { public static void main(String[] args) { Thread t = new MyThread(); //設定執行緒名字 t.setName
("t1"); //開啟執行緒 t.start(); //主執行緒 System.out.println(Thread.currentThread().getName() + " is running"); } }

​ 列印結果:

​ 可以看到是先執行了main執行緒裡面的 sout語句,然後才執行 t1執行緒的語句。說明是併發執行的。

image-20210202150127470

  • 直接重寫Thread方法

    這種方式與上面建立的方式一樣,不過會簡潔一點。

        public static void main(String[
    ] args) { Thread t = new Thread(){ //重寫run方法 public void run() { System.out.println(Thread.currentThread().getName() + " is running"); } }; t.setName("t1"); t.start(); System.out.println(Thread.currentThread().getName() + " is running"); }

二、 使用Runnable配合Thread

優點:

​ 把執行緒任務(要執行的程式碼)分開,通過組合而不是繼承的方式建立了執行緒。這讓程式碼更加的靈活,

​ Thread 代表執行緒

​ Runnable 代表任務

    public static void main(String[] args) {
				//建立一個任務
        Runnable runnable = new Runnable() {
            public void run() {
                System.out.println(Thread.currentThread().getName() + " is running");
            }
        };
				
        //使用Thread類,將runable作為引數建立執行緒
        Thread t = new Thread(runnable , "t2");
				//開啟執行緒
        t.start();

        System.out.println(Thread.currentThread().getName() + " is running");

    }

結果:

image-20210202150127470

  • 小結

    • 方法1 是把執行緒和任務合併在了一起,方法2 是把執行緒和任務分開了

    • 用 Runnable 更容易與執行緒池等高階 API 配合

    • 用 Runnable 讓任務類脫離了 Thread 繼承體系,更靈活。使用了組合的方式建立執行緒。

三、配合Callable介面和Future建立執行緒

​ 這種方式可以獲得執行緒的返回值,FutureTask 能夠接收 Callable 型別的引數,用來處理有返回結果的情況

​ 在使用這個方式建立執行緒之前,首先要明白FutureTask的繼承關係。可以看到FutureTask實現了RunnableFuture介面。而此介面又繼承了Runnable和Future介面。所以FutureTask實際上也是一個Runnable,它除了實現Runnable介面以外,還實現了Future介面。而獲得執行緒的返回值正是通過這個介面進行實現的。

image-20210202153335568

image-20210202153346316

  1. 首先要建立實現了Callable介面的實現類MyCallable,實現call方法。Callable介面是一個泛型介面,其型別就是返回值的型別。實現Callable介面中的call()方法,方法的返回型別與泛型的型別相同。

    class MyCallable implements Callable<Integer>{
    		//重寫call 方法
        public Integer call() throws Exception {
            System.out.println(Thread.currentThread().getName() + " is running");
            //睡眠1s
            Thread.sleep(1000);
            //返回100
            return 100;
        }
      
    }
    
  2. Callable不能直接獲取返回值,需要用FutureTask在外部封裝一下再獲取返回值

    在使用task.get() 方法獲取返回值時,是阻塞式的等待。上面callable介面在返回值之前睡眠了1s,則這個get方法就會阻塞式的等待1s

     public static void main(String[] args) throws ExecutionException, InterruptedException {
    
       			//建立Callable介面實現類
            Callable callable = new MyCallable();
            //建立FutrueTask類
            FutureTask<Integer> task = new FutureTask<>(callable);
    				//建立執行緒,task實現了Runnable介面
            Thread t = new Thread(task,"t1");
            t.start();
    				//呼叫get方法獲取返回值
            System.out.println(Thread.currentThread().getName() + " " + task.get());
    
        }
    
  • 結果

    執行完執行緒t1,然後通過get方法獲得了返回值

    image-20210202154236403