1. 程式人生 > >阿裏推薦的線程使用方法 ThreadPoolExecutor

阿裏推薦的線程使用方法 ThreadPoolExecutor

線程 Android

阿裏推薦原因:使用線程池可以減少創建和銷毀線程上所花的時間以及系統資源的開銷,然後之所以不用Executors自定義線程池,用ThreadPoolExecutor是為了規範線程池的使用,還有讓其他人更好懂線程池的運行規則。

先說一下關於線程的概念

任務:線程需要執行的代碼,也就是Runnable
任務隊列:線程滿了,就任務就放入任務隊列裏等待,等其他任務在線程裏執行完,這個線程就空出來了,任務隊列就將最早來的未執行的任務放入線程執行。
核心線程:線程池一直存在的線程
最大線程數量:指的是線程池所容納的最多的線程數量

ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,

long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue)

第一個是核心線程數量,第二個是最大線程數量,第三個是非核心線程的閑置超時時間,超過這個時間就會被回收,第四個是線程池中的任務隊列模式。

我們主要講這個任務隊列模式

1.LinkedBlockingDeque

我先上一個例子代碼,再來嘮嗑

public class MainActivity extends AppCompatActivity {

Button button;
ThreadPoolExecutor executor;
Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        try {
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName() + " run");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
};
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    button = (Button) findViewById(R.id.btn_record_video);

    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            executor.execute(myRunnable);
            executor.execute(myRunnable);
            executor.execute(myRunnable);
        }
    });

    executor = new ThreadPoolExecutor(3, 6, 3, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());

}

}

當我們點擊一次按鈕

03-03 15:00:43.503 5292-5333/com.example.zth.seven I/System.out: pool-1-thread-1 run
03-03 15:00:43.505 5292-5335/com.example.zth.seven I/System.out: pool-1-thread-3 run
03-03 15:00:43.505 5292-5334/com.example.zth.seven I/System.out: pool-1-thread-2 run

連續點擊兩次

03-03 15:10:47.941 7114-7259/com.example.zth.seven I/System.out: pool-1-thread-1 run

03-03 15:10:47.941 7114-7260/com.example.zth.seven I/System.out: pool-1-thread-2 run
03-03 15:10:47.942 7114-7261/com.example.zth.seven I/System.out: pool-1-thread-3 run
03-03 15:10:49.942 7114-7260/com.example.zth.seven I/System.out: pool-1-thread-2 run
03-03 15:10:49.942 7114-7259/com.example.zth.seven I/System.out: pool-1-thread-1 run
03-03 15:10:49.942 7114-7261/com.example.zth.seven I/System.out: pool-1-thread-3 run

這個時候就可以看出雖然說是最大線程數量是6,但是只用核心線程,不創建新線程,如果核心線程用完了就在隊列裏等待,隊列的大小沒有限制(你可隨便點,他反正後來都會執行)

但是還沒完這個LinkedBlockingDeque還可以設置隊列數量,如果我把隊列設置為2

    executor = new ThreadPoolExecutor(3, 6, 3,
            TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(2));

然後連續點擊2兩次

03-03 15:19:39.851 8971-9013/com.example.zth.seven I/System.out: pool-1-thread-1 run
03-03 15:19:39.851 8971-9014/com.example.zth.seven I/System.out: pool-1-thread-2 run
03-03 15:19:39.851 8971-9015/com.example.zth.seven I/System.out: pool-1-thread-3 run
03-03 15:19:40.045 8971-9016/com.example.zth.seven I/System.out: pool-1-thread-4 run
03-03 15:19:41.851 8971-9013/com.example.zth.seven I/System.out: pool-1-thread-1 run
03-03 15:19:41.851 8971-9015/com.example.zth.seven I/System.out: pool-1-thread-3 run

他這個時候能夠創建四個線程了,為何,首先第一次點擊占了三個核心線程,然後第二次點擊將前兩次任務放入隊列裏,然後隊列滿了就創建一個新線程用來執行最後一個任務

如果我們連續點擊三次,程序在我們點擊第三次就崩潰了,因為線程數量超出最大線程數量了

總結:LinkedBlockingDeque就首先使用核心線程,核心線程用完了就把任務放入隊列裏等待,如果隊列滿了就創建新線程,註意不設置隊列數量,他就默認無限大。

2.SynchronousQueue

我們還是和以前一樣換掉一行代碼

    executor = new ThreadPoolExecutor(3, 6, 3,
            TimeUnit.SECONDS, new SynchronousQueue<Runnable>());

點擊一次

03-03 15:39:31.915 12403-12446/com.example.zth.seven I/System.out: pool-1-thread-2 run
03-03 15:39:31.915 12403-12447/com.example.zth.seven I/System.out: pool-1-thread-3 run
03-03 15:39:31.915 12403-12445/com.example.zth.seven I/System.out: pool-1-thread-1 run

連續點擊兩次

03-03 15:39:53.204 12403-12446/com.example.zth.seven I/System.out: pool-1-thread-2 run
03-03 15:39:53.204 12403-12445/com.example.zth.seven I/System.out: pool-1-thread-1 run
03-03 15:39:53.204 12403-12447/com.example.zth.seven I/System.out: pool-1-thread-3 run
03-03 15:39:53.371 12403-12501/com.example.zth.seven I/System.out: pool-1-thread-5 run
03-03 15:39:53.371 12403-12502/com.example.zth.seven I/System.out: pool-1-thread-6 run
03-03 15:39:53.371 12403-12500/com.example.zth.seven I/System.out: pool-1-thread-4 run

可以看出來當核心線程占滿時他沒有將任務放入隊列裏去等待,而是直接創建新線程取執行任務

連續點擊三次

程序崩潰,因為他創建的線程超過了最大線程數量,

總結:SynchronousQueue很單純,不使用隊列,核心線程用完了就創建新線程,

參考文章:

http://blog.csdn.net/qq_25806863/article/details/71126867

阿裏推薦的線程使用方法 ThreadPoolExecutor