線程池的使用

【線程池簡述】

線程池中,當需要使用線程時,會從線程池中獲取一個空閒線程,線程完成工作時,不會直接關閉線程,而是將這個線程退回到池子,方便其它人使用。

簡而言之,使用線程池後,原來創建線程變成了從線程池獲得空閒線程,關閉線程變成了向池子歸還線程。

 

【線程池帶來的好處】

1.降低資源消耗,通過重複利用已創建的線程降低線程創建和銷燬造成的性能消耗。

2.提高響應速度,當任務到達時,任務可以不需要等待線程創建,可以直接執行。

3.提高線程的可管理性,線程是稀缺資源,如果無限制地創建,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的分配,調優和監控。

 

【線程池接口、類關係一覽】 

 

【說明】

Executor是一個頂級接口,它裏面只聲明一個方法:execute(Runnable command),用來執行傳進去的任務。

ExecutorService接口繼承了Executor接口,並聲明瞭一些方法:submit、shutdown、invokeAll等。

AbstractExecutorService抽象類實現了ExecutorService接口,基本實現了ExecutorService接口的所有方法。

ThreadPoolExecutor繼承了類AbstractExecutorService。

 

【Executors框架】

Executors框架提供了各種類型的線程池,主要有以下幾種工廠方法:

[ newFixedThreadPool()方法 ]

該方法返回一個固定線程數量的線程池。該線程池中的線程數量始終不變,當有一個新的任務提交時,線程池中若有空閒線程,則立即處理。

若沒有空閒線程,則新的任務會被暫存在一個任務隊列中,待有線程空閒時,便處理在任務隊列中的任務。

[ newSingleThreadExecutor()方法 ]

該方法返回一個只有一個線程的線程池。

若多多餘一個任務被提交到該線程池,任務會被保存在一個任務隊列中,待線程空閒,按先入先出順序執行任務。

[ newCachedThreadPool()方法 ]

該方法返回一個可具實際情況調整線程數量的線程池,線程池的線程數量不確定,但若有空閒線程可以複用,則會有優先使用而可以複用線程。若所有線程均在工作,又有新的任務提交,則會創建新的現場處理任務。所有線程在當前任務執行完畢後,將返回線程池進行復用。

[ newSingleThreadScheduledExecutor()方法 ]

該方法返回一個ScheduleExecutorService對象,線程池大小爲1

ScheduleExecutorService接口在ExecutorService接口之上擴張了在給定時間執行某任務的功能,如:在某個固定的延時之後執行,或者週期性執行某個任務。

newScheduleThreadPool()方法 ]

該方法返回一個ScheduleExecutorService對象,但該線程池可以指定線程數量

 

【固定大小的線程池——newFixedThreadPool()】

複製代碼

package com.test.executor;

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

public class ExecutorDemo1 {
    
    public static void main(String[] args) {
        MyTask task = new MyTask();
        ExecutorService es = Executors.newFixedThreadPool(5);  //創建固定線程數大小爲5的線程池
        for(int i=0;i<10;i++){   //依次向線程池提交了10個任務
            es.submit(task);
        }
    }
}

class MyTask implements Runnable{

    @Override
    public void run() {
        System.out.println(System.currentTimeMillis()+":Thread ID:"+Thread.currentThread().getId());
        try{
            Thread.sleep(1000); //1秒
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    
}

複製代碼

【運行結果】

 

【只有一個線程的線程池——newSingleThreadExecutor()】 

複製代碼

package com.test.executor;

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

/**
 * Created by HigginCui on 2018/4/14.
 */
public class ExecutorDemo1 {

    public static void main(String[] args) {
        MyTask myTask = new MyTask();
        //只有一個線程的線程池
        ExecutorService es = Executors.newSingleThreadExecutor();
        for(int i=0;i<10;i++){
            es.submit(myTask);
        }
    }
}

class MyTask implements Runnable{
    @Override
    public void run() {
        System.out.println(System.currentTimeMillis()/1000 + ":Thread ID:" + Thread.currentThread().getId());
        try {
            Thread.sleep(1000);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

複製代碼

【運行結果】

 

【可根據實際情況調整線程數量的線程池——newCacheThreadPool()】

複製代碼

package com.test.executor;

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

/**
 * Created by HigginCui on 2018/4/14.
 */
public class ExecutorDemo1 {

    public static void main(String[] args) {
        MyTask myTask = new MyTask();
        //可根據實際情況調整線程數量的線程池
        ExecutorService es = Executors.newCachedThreadPool();
        for(int i=0;i<10;i++){
            es.submit(myTask);
        }
    }
}

class MyTask implements Runnable{
    @Override
    public void run() {
        System.out.println(System.currentTimeMillis()/1000 + ":Thread ID:" + Thread.currentThread().getId());
        try {
            Thread.sleep(1000);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

複製代碼

【運行結果】

 

【計劃定時任務——newScheduledThreadPool】

複製代碼

package com.test.executor;

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

/**
 * Created by HigginCui on 2018/4/14.
 */
public class ExecutorDemo1 {

    public static void main(String[] args) {

        ScheduledExecutorService ses = Executors.newScheduledThreadPool(10);
        /**
         * scheduleAtFixedRate方法 :如果前面的任務沒有完成,則調度也不會執行!
         * scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);
         */
        ses.scheduleAtFixedRate(new ScheduledTimeTask(), 0, 2, TimeUnit.SECONDS);  //設置每定時2s執行一次
    }

}

class ScheduledTimeTask implements Runnable {
    @Override
    public void run() {
        try {
            //修改這裏的任務執行時間
            Thread.sleep(1000);
            System.out.println( System.currentTimeMillis() / 1000 + " : ThreadId = " + Thread.currentThread().getId());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

複製代碼

【設置任務的執行時間爲1s( <定時的2s )的運行結果】

【設置任務的執行時間爲3s( <定時的2s )的運行結果(即代碼改成Thread.sleep(3000))】

發佈了202 篇原創文章 · 獲贊 88 · 訪問量 28萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章