10分鍾學會java中創建多線程的四種方式


java中創建多線程的四種方式,分別是繼承Thread類,實現Runnable接口,jdk5.0以后又增加了兩種方式:實現Callable接口和使用線程池。在這里我將這四種方式進行總結。

繼承Thread類

步驟

  1. 定義一個類繼承Thread類
  2. 重寫run方法:里面寫線程要運行的任務代碼
  3. 創建Thread子類對象
  4. 調用start方法:開啟線程並調用run方法

代碼

package thread_demo;

public class ThreadDemo {
    public static void main(String[] args) {

        // 創建Thread的子類對象,創建線程。
        Demo d1  = new Demo("旺財");
        Demo d2  = new Demo("小強");
//        d1.run();
//        d2.run();
        d1.start(); //開啟線程,編號從0開始;
        d2.start();

        for(int i=0;i<10;i++){
            System.out.println("主函數:"+Thread.currentThread().getName()+"...i="+i);
        }
    }
}

class Demo extends Thread{ // 定義一個類繼承Thread

    private String name;
    Demo(String name){
        this.name = name;
    }

    // 覆蓋Thread類中的run方法:run方法中定義就是線程要運行的任務代碼
    public void run(){
        show();
    }

    public void show(){
        for(int i=0;i<10;i++){    System.out.println(name+":"+Thread.currentThread().getName()+"...i="+i);
        }
    }
}

結果輸出

主函數:main...i=0
主函數:main...i=1
主函數:main...i=2
主函數:main...i=3
主函數:main...i=4
主函數:main...i=5
主函數:main...i=6
主函數:main...i=7
主函數:main...i=8
主函數:main...i=9
旺財:Thread-0...i=0
旺財:Thread-0...i=1
旺財:Thread-0...i=2
旺財:Thread-0...i=3
旺財:Thread-0...i=4
旺財:Thread-0...i=5
旺財:Thread-0...i=6
旺財:Thread-0...i=7
旺財:Thread-0...i=8
旺財:Thread-0...i=9
小強:Thread-1...i=0
小強:Thread-1...i=1
小強:Thread-1...i=2
小強:Thread-1...i=3
小強:Thread-1...i=4
小強:Thread-1...i=5
小強:Thread-1...i=6
小強:Thread-1...i=7
小強:Thread-1...i=8
小強:Thread-1...i=9

實現Runnable接口

步驟

  1. 定義子類實現Runnable接口
  2. 子類中重寫run方法:將線程的任務代碼封裝到run方法中;
  3. 創建實現子類的對象
  4. 通過Thread類創建線程對象,並將該子類對象作為構造器的參數進行傳遞
  5. 調用Thread類的start方法

代碼

package thread_demo;

public class ThreadDemo2 {
    public static void main(String[] args) {

        Demo2 d = new Demo2();//3.創建實現類對象

        Thread t1 = new Thread(d); // 4.通過Thread類創建線程對象
        t1.start(); // 5. 調用start方法

    }
}

class Demo2 implements Runnable //1. 通過接口的形式擴展Demo類的功能
{
    // 2. 覆蓋run方法;
    public void run(){
        show();
    }
    public void show(){
        for(int i=0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+"...i="+i);
        }
    }
}

結果輸出:

Thread-0...i=0
Thread-0...i=1
Thread-0...i=2
Thread-0...i=3
Thread-0...i=4
Thread-0...i=5
Thread-0...i=6
Thread-0...i=7
Thread-0...i=8
Thread-0...i=9

實現Callable接口

步驟

  1. 創建Callable的實現類:class XxxXxx implements Callable
  2. 重寫call方法,將線程的任務代碼封裝到call方法中:public Object call() throws Exception{}
  3. 創建Callable接口實現子類的對象;
  4. 創建FutureTask的對象,將此Callable接口實現類的對象作為構造器的參數進行傳遞: FutureTask futureTask = new FutureTask(numThread);
  5. 創建Thread對象,並調用start()。將FutureTask的對象作為參數傳遞到Thread類的構造器中:new Thread(futureTask).start();
  6. 獲取Callable中call方法的返回值。 get() 返回值即為FutureTask構造器參數Callable實現類重寫的call()的返回值

代碼

package thread_demo;

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

// 1. 創建一個實現Callable的實現類
class NumThread implements Callable {
    // 2. 實現call方法,將此線程需要執行的操作聲明在call中
    @Override
    public Object call() throws Exception{
        //遍歷1-100打印出偶數之和
        int sum = 0;
        for(int i = 1; i <= 100; i++){
            if((i & 1) == 0){ // i%2 == 0
                System.out.println(i);
                sum += i;
            }
        }
        return sum;
    }
 
}

public class NumThreadTest {
    public static void main(String[] args) {
        // 3. 創建Callable接口實現類的對象;
        NumThread numThread = new NumThread();
        // 4. 將此Callable接口實現類的對象傳遞到FutureTask構造器中,創建FutureTask的對象;
        FutureTask futureTask = new FutureTask(numThread);
        // 5. 將FutureTask的對象作為參數傳遞到Thread類的構造器中,創建Thread對象,並調用start()
        new Thread(futureTask).start();
        try {
            // 6. 獲取Callable中call方法的返回值
            // get() 返回值即為FutureTask構造器參數Callable實現類重寫的call()的返回值
            Object sum = futureTask.get();
            System.out.println("總和是:"+sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("異常");
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }
}

結果輸出:

2
4
6
8
...
98
100
總和是:2550

使用線程池

步驟

  1. 提供指定線程數量的線程池;借助於Executors中的方法;
  2. 執行指定的線程的操作,需要提供實現Runnable接口或Callable接口實現類的對象
    1. Runnable:service.execute(子類對象)
    2. Callable:service.submit(子類對象)
  3. 關閉連接池

注意: 子類對象都可以寫成匿名對象

代碼

package thread_demo;

import java.util.concurrent.*;

/**
 * @ClassName: ThreadDemo2
 * @author: benjamin
 * @version: 1.0
 * @description: TODO
 * @createTime: 2019/04/18/09:32
 */

public class ThreadDemo2 {
    public static void main(String[] args) {

        //1. 提供指定線程數量的線程池;
        ExecutorService service = Executors.newFixedThreadPool(10);
        //2. 執行指定的線程的操作,需要提供實現Runnable接口或Callable接口實現類的對象
//        service.execute(new NumThreadRun()); //適用於Rallable
        Future future = service.submit(new NumThreadCall());//適用於Callable
        try {
            Thread.sleep(5000);// 先延遲5秒
            System.out.println("輸出結果"+future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        //3. 關閉連接池
        service.shutdown();
    }
}


class NumThreadRun implements Runnable {
    // 2. 實現run方法,將次線程需要執行的操作聲明在run中
    @Override
    public void run() {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            if (i % 2 == 0) {
                System.out.println(i+Thread.currentThread().getName());
                sum += i;
            }
        }
        System.out.println("偶數之和="+sum);
    }
}

// 1. 定義Callable的實現類
class NumThreadCall implements Callable {
    // 2. 重寫call方法,將此線程需要執行的操作聲明在call中
    @Override
    public Object call() throws Exception {
        //遍歷1-100打印出奇數之和
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            if ((i & 1) != 0) {
                System.out.println(i+Thread.currentThread().getName());
                sum += i;
            }
        }
        return sum;
    }
}

總結

繼承Thread類和Runnable接口的比較

Thread類實現了Runnable接口public class Thread implements Runnable

都需要重寫run()

Thread中的start和run方法的區別

調用run方法和創建對象調用方法沒有區別;由JVM調用,什么時候調用,執行的過程控制都有操作系統的CPU調度決定

線程中的start方法會創建並啟動一個線程;一個線程對象只能調用一次start()方法啟動,如果重復調用了,則將拋出異常 IllegalThreadStateException

Callable比Runnable的優勢

call()可以有返回值,返回值通過 FutureTask 進行封裝。通過future的get方法獲取返回值
call()可以拋出異常,被外面的操作捕獲,獲取異常的信息;
Callable支持泛型

線程池好處

提高響應速度(減少了創建新線程的時間)
降低資源消耗(重復利用線程池中的線程,不需要每次都創建);
便於線程管理


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM