天天看點

建立線程為何隻有一種方式? - Java

建立多線程可以使用下面四種方式:
  • 繼承Thread
  • 實作Runnable接口
  • 通過Callable和FutureTask建立線程
  • 通過線程池建立線程

第一印象, 你可能會想到這四種建立線程的方式. 可是其實建立線程隻有一種方式, 就是 ​

​new Thread()​

展示上面所說的四種建立線程的方式:

代碼示範

package top.clearlight.blog.hollis.thread;

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

public class CreateThread implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println(Thread.currentThread().getName());

        // 第一種建立方式
        System.out.println("繼承Thread類建立的線程");
        Thread t = new SubClassThread();
        t.start();

        // 第二種建立方式
        System.out.println("實作Runnable接口建立線程");
        CreateThread t2 = new CreateThread();
        new Thread(t2).start();

        // 第三種建立方式
        CallableThread callableThread = new CallableThread();
        FutureTask ft = new FutureTask(callableThread);
        new Thread(ft).start();
        // get()方法會阻塞主線程, 一直等子線程執行完成并傳回後才能繼續執行主線程後面的代碼

        int i = 0;
        // isDone判斷子線程是否執行完, call方法執行完後, 傳回true
        while (!ft.isDone()) {
            // 子線程執行完執行主線程執行其他事情
            System.out.println("main" + i++);
            Thread.sleep(1000);
        }

        System.out.println(ft.get());

        System.out.println("阻塞了3s鐘後," + Thread.currentThread().getName() + "繼續執行");
    }
}

class SubClassThread extends Thread {
    @Override
    public void run() {
        System.out.println(getName());
    }
}

class CallableThread implements Callable {
    @Override
    public Object call() throws Exception {
        System.out.println(Thread.currentThread().getName());
        Thread.sleep(3000);
        return "Hello Thread";
    }
}      

線程池建立線程代碼:

package top.clearlight.blog.hollis.thread;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class CreateThreadPool {

    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
        System.out.println("通過線程池建立線程");
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10));
       /* threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });*/

        // 通過線程池建立線程
        threadPoolExecutor.execute(() -> System.out.println(Thread.currentThread().getName()));

    }
}      

首先, 多線程的狀态第一步, NEW(初始化) : 新建立一個線程對象, 但還沒調用start()方法.

下面開始講解為何建立線程的方式本質上隻有一種!

首先, 擴充Thread, 實際調用父類Thread類的無參構造函數,

建立線程為何隻有一種方式? - Java

進入調用四個參數的構造函數

建立線程為何隻有一種方式? - Java

繼續進入(部分代碼)

建立線程為何隻有一種方式? - Java

是以, ​

​擴充Thread​

​方式其實是調用了Thread類的六個構造參數的構造方法來建立線程.

第二種方式 : ​

​實作Runnable​

​, 通過實作Runnable接口後重寫run方法後建立Runnable對象傳入接受Runnable接口的構造參數

建立線程為何隻有一種方式? - Java
建立線程為何隻有一種方式? - Java

最終還是進入六個參數的構造函數, 隻是傳入的參數不同, 其實建立線程的方式, 本質都是通過傳入不同的參數來調用同一個構造函數.

第三種方式 :

建立線程為何隻有一種方式? - Java
建立線程為何隻有一種方式? - Java

這裡發現, 隻是傳入的target不同.

第四種方式 : 線程池建立線程

建立線程為何隻有一種方式? - Java

進入execute方法

建立線程為何隻有一種方式? - Java
/*
     *  1.如果正在運作的線程少于corePoolSize線程,請嘗試執行以下操作:
         *以給定指令作為第一個線程來啟動新線程
         *任務。對addWorker的調用自動檢查runState和
         * workerCount,是以可以防止假警報的增加
         *在不應該執行的情況下通過傳回false進行線程化。
         *
         * 2.如果任務可以成功排隊,那麼我們仍然需要
         *仔細檢查我們是否應該添加線程
         *(因為現有的自上次檢查後死亡)或
         *自從進入此方法以來,該池已關閉。是以我們
         *重新檢查狀态,并在必要時回退排隊
         *停止,如果沒有,則啟動一個新線程。
         *
         * 3.如果我們無法将任務排隊,那麼我們嘗試添加一個新的
         *線程。如果失敗,我們知道我們已經關閉或飽和
         *并是以拒絕任務。
         * /      

調用​

​addWorker​

建立線程為何隻有一種方式? - Java
建立線程為何隻有一種方式? - Java
建立線程為何隻有一種方式? - Java