线程池

工具类:

  • 缓冲线程池:Executors.newCachedThreadPool();
    可以根据新加入任务自动调整线程池大小,没有任务队列
    源码:
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>()); // 无容量的任务队列
    }
  • 固定容量的线程池:Executors.newFixedThreadPool(3);
    创建固定大小的线程池,新任务添加到任务队列
    源码:
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>()); // 无界的任务队列
  • 定义只有一个线程的线程池:Executors.newSingleThreadExecutor();
    源码:
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

线程池创建方法

1.工具类,不推荐
Executors 返回线程池对象的弊端如下:
FixedThreadPool 和 SingleThreadExecutor : 允许请求的队列长度为 Integer.MAX_VALUE ,可能堆积大量的请求,从而导致OOM。
CachedThreadPool 和 ScheduledThreadPool : 允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致OOM。
所有Executors返回的线程池类型,都是由WhreadPoolExecutor实现
2.ThreadPoolExecutor类,推荐
构造方法:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue)

线程池的启动策略:

1、线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也
不会马上执行它们。
2、当调用 execute() 方法添加一个任务时,线程池会做如下判断:
a. 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
b. 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列。
c. 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这
个任务;
d. 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常,告
诉调用者“我不能再接受任务了”。
3、当一个线程完成任务时,它会从队列中取下一个任务来执行。
4、当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于
corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。

Callable 实现线程池Demo

		ExecutorService pool = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
		long statr = System.currentTimeMillis();
		for (int i = 0; i < 1000; i++) {
			Future<Integer> result= pool.submit(new Call(i)); // 线程的返回值类型为Future<>;
			try {
				System.out.println(result.get(1000, TimeUnit.SECONDS)); // 取出返回值
			} catch (InterruptedException | ExecutionException | TimeoutException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}

submit() 和 excute()方法的区别

  • excute()传入实现了Runnable接口的对象,submit传入实现了Callable<>接口的对象,泛型为返回值类型
  • excute()没有返回值, submit()返回一个Future<>类型的值,泛型为传入Callable的返回值

自定义线程池ThreadPoolExcutExecutor类的参数含义

/**参数含义
* corePoolSize 核心线程池大小
* maximumPoolSize 最大线程池大小
* keepAliveTime 当线程数大于核心时,此为终止前多余的空闲等待新任务最长间。
* TimeUnit keepAliveTime的时间单位
* workQueue 阻塞队列
*
*/

原文地址:https://www.cnblogs.com/zhz-8919/p/10815042.html