java——線程創建與Callable接口解析

Java的線程創建方法

在Java當中,最基本的線程創建方法有兩種,一種是通過繼承Thread類,重寫run方法:

class MyThread extends Thread{
        @Override
        public void run() {
            System.out.println("this is MyThread!");
        }
    }

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

另外一種是實現Runnable接口,重寫run方法:

class MyRunnable implements Runnable{
        @Override
        public void run() {
            System.out.println("this is MyRunnable!");
        }
    }


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

上述兩種方式都能創建一個線程,並啓動運行。查看Thread的源碼,發現Thread是一個Runnable的子類,因此需要實現Ruannable的run方法,所以我們繼承Thread重寫的run方法實際上就是Runnable的run方法。

class Thread implements Runnable {
	private Runnable target;
	@Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
}

另外,Thread內還有一個start方法,從start方法的註釋可以知道,調用該方法時,虛擬機會創建一個線程,並默認執行Thread的run方法。

/**
 * Causes this thread to begin execution; the Java Virtual Machine
 * calls the <code>run</code> method of this thread.
 * */
public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);

        boolean started = false;
        try {
        	//一個本地方法,java本地調用的接口,用於創建線程
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
            
            }
        }
    }

因此,兩種線程創建方式都是利用了在執行start方法啓動線程時,會默認調用run方法的特性:

  • 我們通過繼承Thread類重寫run方法的方式創建線程時,調用start方法,虛擬機創建了線程,由於我們重寫了run方法,因此執行的是我們的方法,而不是Thread類內target屬性的run方法;
  • 我們通過實現Runnable接口創建線程時,Thread的構造函數會將我們實現的Runnable對象,賦值給Thread類內的target屬性,調用Thread的start方法,由虛擬機創建線程,因爲我們沒有重寫Thread的run方法,所以執行的是Thread的run方法,但是該方法調用了target的run方法,因此我們實現的Runnable的run方法得以執行

Callable接口說明

上述的兩種線程創建方法都重寫了run方法,但是run方法沒有返回參數,對於需要線程返回計算結果的情況,
JDK提供了Callable的接口,Callable接口定義了一個帶返回值的call方法,並且返回值是類型參數:

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

因此,通過Callable接口,再結合線程池,可以實現線程返回一個Future對象,通過該對象可以獲取計算結果。注意:Future的get方法,是一個阻塞方法。

class MyCallable implements Callable<String>{
        @Override
        public String call() throws Exception{
            Thread.sleep(2000);
            return " world!";
        }
    }

    public static void main(String[] args) throws Exception{
        ExecutorService executorService=Executors.newSingleThreadExecutor();
        MyCallable myCallable=new MyCallable();
        Future<String> result =executorService.submit(myCallable);
        System.out.println("hello "+result.get());
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章