Java-多線程三種實現方式

說明

Java多線程實現方式主要有三種:繼承Thread類、實現Runnable接口、使用ExecutorService、Callable、Future實現有返回結果的多線程。其中前兩種方式線程執行完後都沒有返回值,只有最後一種是帶返回值的(案例代碼使用jdk1.8)。java

###多線程一些概念網絡

  1. 並行,網絡存在須要同時運行的狀況爲並行,而並行能夠經過多進程、多線程來實現。
  2. 多進程,通常大多數操做系統都支持多進程、系統的並行經過多進程實現。 1.JVM是一個進程,main()是一個線程(主線程)。
  3. Java不支持多進程,並行經過多線程實現。
  4. 多進程內存獨立,java中多線程堆內存共享,棧內存獨立。
  5. 多線程運行時相互獨立的,可是結果會互相影響。

繼承Thread類

Thread類本質上是實現了Runnable接口,是一個線程實例,重寫run()方法,編寫你的線程內容。使用start()方法啓動線程。start()方法的實現被synchronized修飾,同時還調用了start0()方法,而start0()被native修飾(這個使用native修飾是爲了什麼?)再調用run()方法。下面是實現一個多線程demo。多線程

package thread;

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

    public static void main(String[] args) {
        ThreadDemo t = new ThreadDemo();
        ThreadDemo t1 = new ThreadDemo();
        t.start();
        t1.start();
        System.exit(0);
    }
}

###實現Runnable接口 在java中實現的是單繼承,若是你的實現類已經繼承了一個父類,那麼使用繼承Thread方法已經不行了,這樣咱們就來實現Runnable接口。可是實現Runnable接口的線程須要使用Thread類來啓動。例如啓動RunnableDemo 須要實例化一個Thread 對象,把RunnableDemo對象做爲參數傳入。併發

package thread;

public class RunnableDemo implements Runnable{

    @Override
    public void run() {
        System.out.println("RunnableDemo.run()");
    }

    public static void main(String[] args) {
        RunnableDemo r = new RunnableDemo();
        Thread t = new Thread(r);
        Thread t1 = new Thread(r);
        t.start();
        t1.start();
        System.exit(0);
    }
}

###使用ExecutorService、Callable、Future實現有返回結果的多線程 ExecutorService、Callable、Future這個對象實際上都是屬於Executor框架中的功能類。想要詳細瞭解Executor框架的能夠訪問http://www.javaeye.com/topic/366591。框架

####實現Callable接口 實現Callable接口後,能夠獲取一個Future的對象,在該對象上調用get就能夠獲取到Callable任務返回的Object了,再結合線程池接口ExecutorService就能夠實現傳說中有返回結果的多線程了。ide

package thread;

import java.util.Date;
import java.util.concurrent.Callable;

public class CallableDemo implements Callable<Object> {
    private String taskNum;

    public CallableDemo() {
        super();
    }

    public CallableDemo(String taskNum) {
        this.taskNum = taskNum;
    }

    @Override
    public Object call() throws Exception {
        System.out.println(">>" + taskNum + "任務啓動");
        Date dateTmp1 = new Date();
        Thread.sleep(1000);
        Date dateTmp2 = new Date();
        long time = dateTmp2.getTime() - dateTmp1.getTime();
        System.out.println(">>>" + taskNum + "任務終止");
        return taskNum + "任務返回運行結果,當前任務時間【" + time + "毫秒】";
    }
}

在上面的代碼中,能夠明確的知道,線程的主體是在call()方法中實現。 那麼如今再去實現調用,實現多線程,同時獲取返回對象。this

@Test
    public void callableDemoTest() throws ExecutionException, InterruptedException {
        int num = 5;//線程個數
        // 建立一個線程池
        ExecutorService pool = Executors.newFixedThreadPool(num);
        // 保存返回值
        List<Future> list = new ArrayList<>();
        for (int i = 1; i <= 5; i++) {
            //獲取對象
            Callable c = new CallableDemo("task-name-"+i);
            // 執行任務並獲取Future對象
            Future f = pool.submit(c);
            list.add(f);
        }
        // 關閉線程池
        pool.shutdown();
        // 獲取全部併發任務的運行結果
        for (Future f : list) {
            // 從Future對象上獲取任務的返回值,並輸出到控制檯
            System.out.println(">>>" + f.get().toString());
        }
    }
相關文章
相關標籤/搜索