多線程—線程三種創建方式及對比

線程創建的3種方法:

1、繼承Thread類並重寫run方法

Thread類方法:

Thread Thread.currentThread() :獲得當前線程的引用。獲得當前線程後對其進行操作。
Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() :返回線程由於未捕獲到異常而突然終止時調用的默認處理程序。
int Thread.activeCount():當前線程所在線程組中活動線程的數目。
void dumpStack() :將當前線程的堆棧跟蹤打印至標準錯誤流。
int enumerate(Thread[] tarray) :將當前線程的線程組及其子組中的每一個活動線程複製到指定的數組中。
Map<Thread,StackTraceElement[]> getAllStackTraces() :返回所有活動線程的堆棧跟蹤的一個映射。
boolean holdsLock(Object obj) :當且僅當當前線程在指定的對象上保持監視器鎖時,才返回 true。
boolean interrupted() :測試當前線程是否已經中斷。
void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh) :設置當線程由於未捕獲到異常而突然終止,並且沒有爲該線程定義其他處理程序時所調用的默認處理程序。
void sleep(long millis) :休眠指定時間
void sleep(long millis, int nanos) :休眠指定時間
void yield() :暫停當前正在執行的線程對象,並執行其他線程。意義不太大
void checkAccess() :判定當前運行的線程是否有權修改該線程。
ClassLoader getContextClassLoader() :返回該線程的上下文 ClassLoader。
long getId() :返回該線程的標識符。
String getName() :返回該線程的名稱。
int getPriority() :返回線程的優先級。
StackTraceElement[] getStackTrace() :返回一個表示該線程堆棧轉儲的堆棧跟蹤元素數組。
Thread.State getState() :返回該線程的狀態。
ThreadGroup getThreadGroup() :返回該線程所屬的線程組。
Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() :返回該線程由於未捕獲到異常而突然終止時調用的處理程序。
void interrupt() :中斷線程。
boolean isAlive() :測試線程是否處於活動狀態。
boolean isDaemon() :測試該線程是否爲守護線程。
boolean isInterrupted():測試線程是否已經中斷。
void join() :等待該線程終止。
void join(long millis) :等待該線程終止的時間最長爲 millis 毫秒。
void join(long millis, int nanos) :等待該線程終止的時間最長爲 millis 毫秒 + nanos 納秒。
void run() :線程啓動後執行的方法。
void setContextClassLoader(ClassLoader cl) :設置該線程的上下文 ClassLoader。
void setDaemon(boolean on) :將該線程標記爲守護線程或用戶線程。
void start():使該線程開始執行;Java 虛擬機調用該線程的 run 方法。
String toString():返回該線程的字符串表示形式,包括線程名稱、優先級和線程組。

實現案例: 

public class ExtendThreadTest extends Thread {

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(getName() + " : run " + i);
        }
    }

    public static void main(String[] args) {
        Thread thread1 = new ExtendThreadTest();
        Thread thread2 = new ExtendThreadTest();
        
        thread1.start();
        thread2.start();
        
        for (int i = 0; i < 3; i++) {
            System.out.println("main : run " + i);
        }
    }
}

2、實現Runable接口並重寫run方法。Runable接口只有一個run方法。

public class ImplementsRunnableTest implements Runnable {

    private int tick = 10;
    
    public void run() {
        while (true) {
            if(tick > 0){
                System.out.println(Thread.currentThread().getName() + "..." + tick--);
            }
        }
    }

    public static void main(String[] args) {
        ImplementsRunnableTest t = new ImplementsRunnableTest();
        new Thread(t).start();
        new Thread(t).start();
    }
}

3、通過實現Callable和Future接口創建

public interface Callable<V> {
    V call() throws Exception; //類型參數V即爲異步方法call的返回值類型。
}

Future可以對具體的Runnable或者Callable任務的執行結果進行取消、查詢是否完成以及獲取結果。可以通過get方法獲取執行結果,該方法會阻塞直到任務返回結果。get方法獲取到call方法返回的數據。

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();                    //表示任務是否被取消成功,如果在任務正常完成前被取消成功,則返回 true。
    boolean isDone();                         //任務是否已經完成,若任務完成,則返回true
    V get() throws InterruptedException, ExecutionException; //獲取執行結果,這個方法會阻塞
    V get(long timeout, TimeUnit unit)                       //在指定時間內,還沒獲取到結果,就直接返回null
        throws InterruptedException, ExecutionException, TimeoutException;
}

java.util.concurrent包已經有自帶的Future實現類FutureTask<V>,直接用就可以了,FutureTask實現了RunnableFuture<V>接口,RunnableFuture<V>又實現了Runnable接口和Future接口。

實現案例: 

public class CallableTest implements Callable<String> {

    //重寫Callable接口方法
    public String call() throws Exception {
        return Thread.currentThread().getName();
    }

    public static void main(String[] args) {
        // 創建callable實現類實例
        CallableTest t = new CallableTest();
        // 使用FutureTask類來包裝Callable對象
        FutureTask<String> ft1 = new FutureTask<String>(t);
        FutureTask<String> ft2 = new FutureTask<String>(t);
        new Thread(ft1).start();
        new Thread(ft2).start();
        try {
            System.out.println(ft1.get());
            System.out.println(ft2.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

對比

  • 通過繼承Thread類的線程,一個類只能繼承一個父類,使得該方式具有一定的侷限性。
  • 實現接口的類,再結合Thread類來實現的線程,只是實現了接口類,還可以繼承其他類,相對較靈活,且call()方法是一個有返回值而且拋異常的方法。實現接口創建的線程可以放入線程池來管理,而繼承Thread類創建的線程不可以放入線程池。
  • 三種方式最終都是通過調用start()方法來實現多線程。切記不能直接調用Thread類或Runnable對象的run()方法,因爲直接調用run()方法,只會執行同一個線程中的任務,而不會啓動新線程。調用start()方法將會創建一個執行run()方法的線程。

start()方法用了synchronized關鍵字修飾且內部調用start0()

 //native方法,JVM創建並啓動線程,並調用run方法
 private native void start0();

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章