线程池的大小如何设置(美团技术给出动态更改线程大小的方案)

线程池大小的设置一直是在开发中比较难的点,网上没有找到一个比较合适的设置的方案。
这个是美团技术整理一份关于网上比较多的一些线程设置方案。
在这里插入图片描述

按照网上的方案设置线程池的大小,基本都是对线程池的大小偏高。下面是美团大佬给出的方案。

Java线程池实现原理及其在美团业务中的实践

这篇博客,主要在这个方案下,写一下代码方面的如果改变比较关注的核心线程、最大线程数、队列长度的调整。这里在调整整个线程池大小的时候有两个需要注意点:

1、jdk 的BlockingQueue 的capacity 是final修饰的。

其实ThreadPoolExecutor提供设置最大线程池和核心线程的大小

executor.setMaximumPoolSize(20);
 executor.setCorePoolSize(10);

但在队列长度设置的的key发现jdk设置容量的地方,
在这里插入图片描述
在这里插入图片描述
可以看到阻塞队列的长度是 final修饰的,无法改变其容量大小,因此为了改变容量大小。我们可以自定义阻塞队列,只需要改将阻塞队列改一个名字,并将其去掉final修饰。在这里插入图片描述

2、在ThreadPoolExecutor#getTask的时候,如果当前工作线程大于核心最大线程,不能够获取到runnable任务。
在这里插入图片描述

如果当前工作线程大于核心最大线程,不能够获取到runnable任务,因此在设置最大线程数和核心线程的大小的时候,需要先设置最大线程数,再去设置核心线程数。

下面是代码的具体实现:

package com.yin.freemakeradd.utils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.*;

/**
 * @author yin
 * @Date 2020/4/25 16:51
 * @Method
 */
public class DynamicThreadPool {


    /**
     * 构建一个普通线程池
     * @return
     */
    private static ThreadPoolExecutor buildThreadPoolExecutor(int corePoolSize,
                                                             int maximumPoolSize,
                                                             long keepAliveTime,
                                                             TimeUnit unit,
                                                             DynamicLinkedBlockingQueue<Runnable> workQueue,
                                                             String threadName){
        return new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
                keepAliveTime,unit, workQueue, new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setName(threadName);
                thread.setDaemon(true);
                return thread;
            }
        });
    }

    public static void main(String[] args) throws InterruptedException {
        dynamicThreadPool();
    }


    private static void dynamicThreadPool() throws InterruptedException {
        ThreadPoolExecutor executor = buildThreadPoolExecutor(2, 5,
                60, TimeUnit.SECONDS, new DynamicLinkedBlockingQueue<>(10), "dynamicPoolTestThread");

        for (int i = 0; i < 15; i++) {

            final int j = i;
            executor.submit(()->{
                printThreadPoolStatus(executor, "创建任务");
                try {
                    TimeUnit.SECONDS.sleep(10+2*j);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });

        }
        sleepSeconds(1);
        printThreadPoolStatus(executor, "完成任务创建");

        DynamicLinkedBlockingQueue<Runnable> queue =(DynamicLinkedBlockingQueue) executor.getQueue();
        queue.setCapacity(20);

        executor.setMaximumPoolSize(20);
        executor.setCorePoolSize(10);




        sleepSeconds(1);

        printThreadPoolStatus(executor, "改变设置之后");
        Thread.currentThread().join();

    }


    private static void sleepSeconds(int time){
        try {
            TimeUnit.SECONDS.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss SSS");
    private static void printThreadPoolStatus(ThreadPoolExecutor executor, String name) {
        BlockingQueue<Runnable> queue = executor.getQueue();
        System.out.println(formatter.format(LocalDateTime.now())+"::"+name + "::" + Thread.currentThread().getName() + "::" +
                "核心线程数 :" + executor.getCorePoolSize() +
                "::最大线程数 :" + executor.getMaximumPoolSize() +
                "::活动线程数 :" + executor.getActiveCount()+
        "::任务完成数"+executor.getCompletedTaskCount()+
        "::队列使用 :"+queue.size()+"::队列未使用 :"+queue.remainingCapacity()+"::队列总共大小 :"+(queue.size()+queue.remainingCapacity()));
    }




}

自定义队列:

/*
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

/*
 *
 *
 *
 *
 *
 * Written by Doug Lea with assistance from members of JCP JSR-166
 * Expert Group and released to the public domain, as explained at
 * http://creativecommons.org/publicdomain/zero/1.0/
 */


import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;

/**
 * An optionally-bounded {@linkplain BlockingQueue blocking queue} based on
 * linked nodes.
 * This queue orders elements FIFO (first-in-first-out).
 * The <em>head</em> of the queue is that element that has been on the
 * queue the longest time.
 * The <em>tail</em> of the queue is that element that has been on the
 * queue the shortest time. New elements
 * are inserted at the tail of the queue, and the queue retrieval
 * operations obtain elements at the head of the queue.
 * Linked queues typically have higher throughput than array-based queues but
 * less predictable performance in most concurrent applications.
 *
 * <p>The optional capacity bound constructor argument serves as a
 * way to prevent excessive queue expansion. The capacity, if unspecified,
 * is equal to {@link Integer#MAX_VALUE}.  Linked nodes are
 * dynamically created upon each insertion unless this would bring the
 * queue above capacity.
 *
 * <p>This class and its iterator implement all of the
 * <em>optional</em> methods of the {@link Collection} and {@link
 * Iterator} interfaces.
 *
 * <p>This class is a member of the
 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
 * Java Collections Framework</a>.
 *
 * @param <E> the type of elements held in this collection
 * @author Doug Lea
 * @since 1.5
 */
public class DynamicLinkedBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {
    private static final long serialVersionUID = -6903933977591709194L;

    /*
     * A variant of the "two lock queue" algorithm.  The putLock gates
     * entry to put (and offer), and has an associated condition for
     * waiting puts.  Similarly for the takeLock.  The "count" field
     * that they both rely on is maintained as an atomic to avoid
     * needing to get both locks in most cases. Also, to minimize need
     * for puts to get takeLock and vice-versa, cascading notifies are
     * used. When a put notices that it has enabled at least one take,
     * it signals taker. That taker in turn signals others if more
     * items have been entered since the signal. And symmetrically for
     * takes signalling puts. Operations such as remove(Object) and
     * iterators acquire both locks.
     *
     * Visibility between writers and readers is provided as follows:
     *
     * Whenever an element is enqueued, the putLock is acquired and
     * count updated.  A subsequent re
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值