時隔一年後的面經總結之線程池

面試廠家360,技術面三面。問題:你用過哪些線程池?請介紹一下。

我最常用的線程池是new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) ,以下就是我最常用的線程池代碼,我也向面試官簡單介紹了我的用法,但答案不是面試官想要的。直接上代碼:

ThreadPoolExecutorTest.java

package com.bds.lww.demo.thread;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author liuww 2019/12/19
 */
public class ThreadPoolExecutorTest {

	public static void main(String[] args) {
		// 創建一個線程的線程池
		ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
		
		for (int i = 0; i < 10; i++) {
			pool.execute(new ThreadPoolTask(i));
		}
		
		try {
            //等待所有線程執行完畢當前任務。
			pool.shutdown();

            boolean loop = true;
            do {
                //等待所有線程執行完畢當前任務結束
                loop = !pool.awaitTermination(2, TimeUnit.SECONDS);//等待2秒
            } while (loop);

            if (loop != true) {
                System.out.println("所有線程執行完畢");
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println("耗時:" + (System.currentTimeMillis() - System.currentTimeMillis()));
        }
	}
}

ThreadPoolTask.java

package com.bds.lww.demo.thread;
/**
 * @author liuww 2019/12/19
 */
public class ThreadPoolTask implements Runnable {
	
	private Object attachData;
	
	ThreadPoolTask(Object tasks) {
        this.attachData = tasks;
    }

	@Override
	public void run() {
		try {
            System.out.println("開始執行任務:" + attachData + "任務,使用的線程池,線程名稱:" + Thread.currentThread().getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
        attachData = null;
	}

}

執行結果:

開始執行任務:1任務,使用的線程池,線程名稱:pool-1-thread-2
開始執行任務:3任務,使用的線程池,線程名稱:pool-1-thread-2
開始執行任務:4任務,使用的線程池,線程名稱:pool-1-thread-2
開始執行任務:5任務,使用的線程池,線程名稱:pool-1-thread-2
開始執行任務:6任務,使用的線程池,線程名稱:pool-1-thread-2
開始執行任務:7任務,使用的線程池,線程名稱:pool-1-thread-2
開始執行任務:8任務,使用的線程池,線程名稱:pool-1-thread-2
開始執行任務:9任務,使用的線程池,線程名稱:pool-1-thread-2
開始執行任務:0任務,使用的線程池,線程名稱:pool-1-thread-1
開始執行任務:2任務,使用的線程池,線程名稱:pool-1-thread-3
所有線程執行完畢
耗時:0

 源碼分析 ,ThreadPoolExecutor 的構造函數

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

其實java的Executors工廠已經實現了適用於多個場景的線程池,而內部就是以上面的方式實現的。可惜我才疏學淺,盡然不知道。

1.newFixedThreadPool()

由於使用了LinkedBlockingQueue所以maximumPoolSize沒用,當corePoolSize滿了之後就加入到LinkedBlockingQueue隊列中。
每當某個線程執行完成之後就從LinkedBlockingQueue隊列中取一個。
所以這個是創建固定大小的線程池。

源碼分析:

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(
            nThreads,
            nThreads,
            0L,
            TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>());
}

2.newSingleThreadPool()

創建線程數爲1的線程池,由於使用了LinkedBlockingQueue所以maximumPoolSize 沒用,corePoolSize爲1表示線程數大小爲1,滿了就放入隊列中,執行完了就從隊列取一個。

源碼分析

public static ExecutorService newSingleThreadExecutor() {
    return new Executors.FinalizableDelegatedExecutorService
            (
                    new ThreadPoolExecutor(
                            1,
                            1,
                            0L,
                            TimeUnit.MILLISECONDS,
                            new LinkedBlockingQueue<Runnable>())
            );
}

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
            Executors.defaultThreadFactory(), defaultHandler);
}

3.newCachedThreadPool()

創建可緩衝的線程池。沒有大小限制。由於corePoolSize爲0所以任務會放入SynchronousQueue隊列中,SynchronousQueue只能存放大小爲1,所以會立刻新起線程,由於maxumumPoolSizeInteger.MAX_VALUE所以可以認爲大小爲2147483647。受內存大小限制。

源碼分析

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(
            0,
            Integer.MAX_VALUE,
            60L,
            TimeUnit.SECONDS,
            new SynchronousQueue<Runnable>());
}

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
            Executors.defaultThreadFactory(), defaultHandler);
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章