1. 程式人生 > >Java多線程的四種實現方式

Java多線程的四種實現方式

util println 通過 泛型 pri png 返回值 sch get

1.Java多線程實現的方式有四種:
1.繼承Thread類,重寫run方法
2.實現Runnable接口,重寫run方法,實現Runnable接口的實現類的實例對象作為Thread構造函數的target
3.通過Callable和FutureTask創建線程
4.通過線程池創建線程
2.Thread實現方式
繼承Thread類,重寫run()方法,創建Thread對象調用start()方法啟動線程。

public class ThreadDemo extends Thread {
    @Override
    public void run() {
        int t = 1;
        
for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + " " + (t++)); } } public static void main(String[] args) { ThreadDemo td1 = new ThreadDemo(); ThreadDemo td2 = new ThreadDemo(); td1.setName("Thread1"); td2.setName(
"Thread2"); td1.start(); td2.start(); } }

結果:

技術分享圖片

3.Runnable實現方式
實現Runnable接口,實現run()方法,接口的實現類的實例作為Thread的target傳入帶參的Thread構造函數,調用start()方法啟動線程。

public class RunnableDemo implements Runnable {
    @Override
    public void run() {
        int t = 1;
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() 
+ " " + (t++)); } } public static void main(String[] args) { RunnableDemo rd = new RunnableDemo(); Thread tr1 = new Thread(rd); Thread tr2 = new Thread(rd); tr1.setName("Thread1"); tr2.setName("Thread2"); tr1.start(); tr2.start(); } } }

結果:

技術分享圖片

3.Callable和FutureTask創建線程實現方式
(1)創建Callable接口的實現類 ,並實現Call方法;
(2)創建Callable實現類的實現,使用FutureTask類包裝Callable對象,該FutureTask對象封裝了Callable對象的Call方法的返回值 ;
(3)使用FutureTask對象作為Thread對象的target創建並啟動線程;
(4)調用FutureTask對象的get()來獲取子線程執行結束的返回值。

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

public class CallableFutureTaskDemo implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int t = 1;
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "  " + (t++));
        }
        return t;
    }

    public static void main(String[] args) {
        Callable<Integer> cftd1 = new CallableFutureTaskDemo();
        Callable<Integer> cftd2 = new CallableFutureTaskDemo();
        FutureTask<Integer> ft1 = new FutureTask<>(cftd1);
        FutureTask<Integer> ft2 = new FutureTask<>(cftd2);
        Thread t1 = new Thread(ft1);
        Thread t2 = new Thread(ft2);
        t1.setName("Thread1");
        t2.setName("Thread2");
        t1.start();
        t2.start();
        try {
            System.out.println(ft1.get());
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

結果:

技術分享圖片

5.線程池實現方式

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorDemo implements Runnable {
    private static int POOL_NUM = 2;  //線程池數量

    @Override
    public void run() {
        int t = 1;
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "  " + (t++));
        }
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        for (int i = 0; i < POOL_NUM; i++) {
            ExecutorDemo ed = new ExecutorDemo();
            executorService.execute(ed);
        }
        executorService.shutdown();
    }
}

結果:

技術分享圖片

java裏面的線程池的頂級接口是Executor,Executor並不是一個線程池,而只是一個執行線程的工具,而真正的線程池是ExecutorService。
java中的有哪些線程池?
1.newCachedThreadPool創建一個可緩存線程池程
2.newFixedThreadPool 創建一個定長線程池
3.newScheduledThreadPool 創建一個定長線程池
4.newSingleThreadExecutor 創建一個單線程化的線程池
這裏的例子用到的就是newFixedThreadPool 。

6.總結
(1)實現Runnable接口比繼承Thread類更具有優勢!Runnable接口適合多個相同的程序代碼的線程去處理同一個資源,可以避免java中的單繼承的限制,增加程序的健壯性,而且代碼可以被多個線程共享,實現代碼和數據獨立。

(2)使用線程池可以減少了創建和銷毀線程的次數,每個工作線程都可以被重復利用,可執行多個任務,可以根據系統的承受能力,調整線程池中工作線線程的數量。

(3)實際應用中,可以通過一個boolean標誌位來結束線程。

(4)ExecutorService、Callable都是屬於Executor框架。返回結果的線程是在JDK1.5中引入的新特征,還有Future接口也是屬於這個框架,有了這種特征得到返回值更方便。
執行Callable任務後,可以獲取一個Future的對象,在該對象上調用get就可以獲取到Callable任務返回的值(由泛型決定)了。get()方法是阻塞的,即線程無返回結果,get方法會一直等待。此外,ExecutoreService提供了submit()方法,傳遞一個Callable或Runnable,返回Future。如果Executor後臺線程池還沒有完成Callable的計算,這調用返回Future對象的get()方法,會阻塞直到計算完成。

技術分享圖片

Java多線程的四種實現方式