时隔一年后的面经总结之线程池

面试厂家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);
}

 

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