Java線程池常用方法

jopen 10年前發布 | 14K 次閱讀 Java Java開發

在Java5之后,并 發線程這塊發生了根本的變化,最重要的莫過于新的啟動、調度、管理線程的一大堆API了。在Java5以后,通過Executor來啟動線程比用 Thread的start()更好。在新特征中,可以很容易控制線程的啟動、執行和關閉過程,還可以很容易使用線程池的特性。

通過java.util.concurrent.ExecutorService接口對象來執行任務,該接口對象通過工具類java.util.concurrent.Executors的靜態方法來創建。

  Executors此包中所定義的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 類的工廠和實用方法。

   ExecutorService提供了管理終止的方法,以及可為跟蹤一個或多個異步任務執行狀況而生成 Future 的方法。 可以關閉 ExecutorService,這將導致其停止接受新任務。關閉后,執行程序將最后終止,這時沒有任務在執行,也沒有任務在等待執行,并且無法提交新任 務。

  executorService.execute(new TestRunnable());

  1、創建ExecutorService

  通過工具類java.util.concurrent.Executors的靜態方法來創建。

  Executors此包中所定義的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 類的工廠和實用方法。

  比如,創建一個ExecutorService的實例,ExecutorService實際上是一個線程池的管理工具:

  ExecutorService executorService = Executors.newCachedThreadPool();

  ExecutorService executorService = Executors.newFixedThreadPool(3);

  ExecutorService executorService = Executors.newSingleThreadExecutor();

  2、將任務添加到線程去執行

  當將一個任務添加到線程池中的時候,線程池會為每個任務創建一個線程,該線程會在之后的某個時刻自動執行。

  三、關閉執行服務對象

  executorService.shutdown();

package javaBasic;

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

/**
 * 創建由Callable對象組成的的執行線程池
 * 
 * @author markGao
 * 
 */
public class ExecutorServiceSample {

    public static void main(String[] args) {
        int numberOfThreads = java.lang.Runtime.getRuntime()
                .availableProcessors();

        ExecutorService pool = Executors.newFixedThreadPool(numberOfThreads);

        for (int i = 0; i < numberOfThreads; i++) {
            pool.execute(new TestRunnable());
            System.out.println("************* execute Processors" + i
                    + " *************");
        }
        pool.shutdown();

    }

}

/**
 * Runnable任務沒有返回值
 * 
 * @author markGao
 * 
 */
class TestRunnable implements Runnable {
    public void run() {
        System.out.println(Thread.currentThread().getName() + "線程被調用了。");
        while (true) {
            try {
                Thread.sleep(5000);
                System.out.println(Thread.currentThread().getName());
                
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

五、獲取任務的執行的返回值

  在Java5之 后,任務分兩類:一類是實現了Runnable接口的類,一類是實現了Callable接口的類。兩者都可以被ExecutorService執行,但是 Runnable任務沒有返回值,而Callable任務有返回值。并且Callable的call()方法只能通過ExecutorService的 submit(Callable<T> task) 方法來執行,并且返回一個 <T> Future<T>,是表示任務等待完成的 Future.

  public interface Callable<V>返回結果并且可能拋出異常的任務。實現者定義了一個不帶任何參數的叫做 call 的方法。

  Callable 接口類似于 Runnable,兩者都是為那些其實例可能被另一個線程執行的類設計的。但是 Runnable 不會返回結果,并且無法拋出經過檢查的異常。

  Executors 類包含一些從其他普通形式轉換成 Callable 類的實用方法。

  Callable中的call()方法類似Runnable的run()方法,就是前者有返回值,后者沒有。

  當將一個Callable的對象傳遞給ExecutorService的submit方法,則該call方法自動在一個線程上執行,并且會返回執行結果Future對象。

  同樣,將Runnable的對象傳遞給ExecutorService的submit方法,則該run方法自動在一個線程上執行,并且會返回執行結果Future對象,但是在該Future對象上調用get方法,將返回null.

package javaBasic;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class CallableDemo {
    public static void main(String[] args) {
        // get available Processors
        int numberOfThreads = java.lang.Runtime.getRuntime()
                .availableProcessors();
        ExecutorService executorService = Executors
                .newFixedThreadPool(numberOfThreads);
        List<Future<String>> resultList = new ArrayList<Future<String>>();

        // create ten tasks
        for (int i = 0; i < 10; i++) {
            // use ExecutorService to execute taks of Callable Type, and save
            // result into future.
            Future<String> future = executorService
                    .submit(new TaskWithResult(i));
            // task result save into List
            resultList.add(future);
        }

        // Traversal Task
        for (Future<String> fs : resultList) {
            try {
                // print every thread result
                System.out.println(fs.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            } finally {
                executorService.shutdown();
            }
        }
    }
}

class TaskWithResult implements Callable<String> {
    private int id;

    public TaskWithResult(int id) {
        this.id = id;
    }

    public String call() throws Exception {
        System.out.println(System.currentTimeMillis()
                + " Start call() invoked " + id + " "
                + Thread.currentThread().getName());
        // for (int i = 9999999; i > 0; i--)
        // ;
        Thread.sleep(5000);
        return System.currentTimeMillis() + " End call() invoked " + id
                + "    " + Thread.currentThread().getName();
    }
}

線程池可以解決兩個不 同問題:由于減少了每個任務調用的開銷,它們通常可以在執行大量異步任務時提供增強的性能,并且還可以提供綁定和管理資源(包括執行集合任務時使用的線 程)的方法。每個 ThreadPoolExecutor 還維護著一些基本的統計數據,如完成的任務數。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!