線程池

什麼是線程池。
線程池,其實就是一個容納多個線程的容器,其中的線程可以反覆使用,省去了頻繁創建線程對象的操作,無需反覆創建線程而消耗過多資源。

爲什麼要使用線程池。
在java中,如果每個請求到達就創建一個新線程,開銷是相當大的。在實際使用中,創建和銷燬線程花費的時間和消耗的系統資源都相當大,甚至可能要比在處理實際的用戶請求的時間和資源要多的多。除了創建和銷燬線程的開銷之外,活動的線程也需要消耗系統資源。如果在一個jvm裏創建太多的線程,可能會使系統由於過度消耗內存或“切換過度”而導致系統資源不足。爲了防止資源不足,需要採取一些辦法來限制任何給定時刻處理的請求數目,儘可能減少創建和銷燬線程的次數,特別是一些資源耗費比較大的線程的創建和銷燬,儘量利用已有對象來進行服務。
線程池主要用來解決線程生命週期開銷問題和資源不足問題。通過對多個任務重複使用線程,線程創建的開銷就被分攤到了多個任務上了,而且由於在請求到達時線程已經存在,所以消除了線程創建所帶來的延遲。這樣,就可以立即爲請求服務,使用應用程序響應更快。另外,通過適當的調整線程中的線程數目可以防止出現資源不足的情況。

使用線程池方式--Runnable接口
通常,線程池都是通過線程池工廠創建,再調用線程池中的方法獲取線程,再通過線程去執行任務方法。

Executors:線程池創建工廠類
public static ExecutorService newFixedThreadPool(int nThreads):返回線程池對象
ExecutorService:線程池類
Future<?> submit(Runnable task):獲取線程池中的某一個線程對象,並執行
Future接口:用來記錄線程任務執行完畢後產生的結果。線程池創建與使用

使用線程池中線程對象的步驟:
創建線程池對象
創建Runnable接口子類對象
提交Runnable接口子類對象
關閉線程池

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

public class Chi {
    public static void main(String[] args) {
        /*沒有線程池的寫法
        Runnable r = new MyRunnable();
        Thread t = new Thread(r);
        t.start();*/

ExecutorService e =Executors.newFixedThreadPool(2);//創建一個包含兩個線程的線程池
        Runnable r = new MyRunnable();
        e.submit(r);//獲取線程池中的某一個線程對象,然後調用runnable接口中的run方法
        e.submit(r);
        e.submit(r);
        e.submit(r);//注意run方法運行完,線程中的線程並不消耗,而是歸還到池中
        e.shutdown();
    }
    }
    class MyRunnable implements Runnable{
@Override
    public void run() {
        System.out.println("給我一個線程:"+Thread.currentThread().getName());
        try {
            System.out.println("線程開始消耗資源"+Thread.currentThread().getName());
            Thread.sleep(2000);
            System.out.println("線程使用完畢"+Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("歸還到線程池中"+Thread.currentThread().getName());
    }
    }

運行結果:

給我一個線程:pool-1-thread-1
給我一個線程:pool-1-thread-2
線程開始消耗資源pool-1-thread-1
線程開始消耗資源pool-1-thread-2
線程使用完畢pool-1-thread-2
歸還到線程池中pool-1-thread-2
給我一個線程:pool-1-thread-2
線程開始消耗資源pool-1-thread-2
線程使用完畢pool-1-thread-1
歸還到線程池中pool-1-thread-1
給我一個線程:pool-1-thread-1
線程開始消耗資源pool-1-thread-1
線程使用完畢pool-1-thread-1
歸還到線程池中pool-1-thread-1
線程使用完畢pool-1-thread-2
歸還到線程池中pool-1-thread-2

使用線程池方式—Callable接口
Callable接口:與Runnable接口功能相似,用來指定線程的任務。其中的call()方法,用來返回線程任務執行完畢後的結果,call方法可拋出異常。
ExecutorService:線程池類
<T> Future<T> submit(Callable<T> task):獲取線程池中的某一個線程對象,並執行線程中的call()方法
V get() 獲取Future對象中封裝的數據結果
Future接口:用來記錄線程任務執行完畢後產生的結果。線程池創建與使用

使用線程池中線程對象的步驟:
創建線程池對象
創建Callable接口子類對象
提交Callable接口子類對象
關閉線程池

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

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

        //MyCallable my=new MyCallable(1,1);
        //  FutureTask<Integer> ft = new FutureTask<Integer>(my);
//new Thread(ft,"有返回值的線程").start();    
    //      Integer integer = ft.get();
        //   System.out.println("子線程的返回值:"+integer);

            //創建線程池對象
            ExecutorService threadPool = Executors.newFixedThreadPool(2);
            //創建一個Callable接口子類對象
            MyCallable c = new MyCallable(100, 200);
            MyCallable c2 = new MyCallable(10, 20);
            //獲取線程池中的線程,調用Callable接口子類對象中的call()方法, 完成求和操作
            Future<Integer> result = threadPool.submit(c);
            //此 Future 的 get 方法所返回的結果類型
            Integer sum= result.get();
            System.out.println("sum=" + sum);
            Future<Integer> result1 = threadPool.submit(c2);
            Integer sum1 =  result1.get();
            System.out.println("sum1=" + sum1);
            Future<Integer> result2 = threadPool.submit(c2);
            Integer sum2 =  result2.get();
            System.out.println("sum2=" + sum2);
            Future<Integer> result3 = threadPool.submit(c2);
            Integer sum3 =  result3.get();
            System.out.println("sum3=" + sum3);
            } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
    }
class MyCallable implements Callable<Integer>{
    //成員變量
    int x = 5;
    int y = 3;
    //構造方法
    public MyCallable(int x, int y){
        this.x = x;
        this.y = y;
    }
    @Override
    public Integer call() throws Exception {
        System.out.println("給我一個線程"+Thread.currentThread().getName());
        System.out.println("線程開始消耗資源"+Thread.currentThread().getName());
        Thread.sleep(2000);
        System.out.println("線程使用完畢"+Thread.currentThread().getName());
        System.out.println("歸還到線程池中"+Thread.currentThread().getName());
        return x+y;
    }   
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章