• 线程池的取值(三)阻塞队列边界取值+1,还需要全面了解线程池源码【yetdone】


    在上一篇中,线程池的取值(二)设计吞吐量 重要使用无界的LinkedBlockingQueue来接收等待队列,我们将阻塞队列改为36来看看:

    import java.util.concurrent.*;
    
    /**
     * https://www.cnblogs.com/silyvin/p/11806859.html
     * https://www.cnblogs.com/silyvin/p/11875907.html
     * Created by joyce on 2019/11/6.
     */
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.SECONDS)
    @Threads(40)
    @State(Scope.Thread)
    public class MyThread {
    
        private static final ThreadPoolExecutor MQ_POOL = new ThreadPoolExecutor(
                4, 4, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(36),
                new DefaultThreadFactory("mq-", true));
        
        public static class action implements Callable<Integer> {
    
            @Override
            public Integer call() throws Exception {
                int a = 0;
                Thread.sleep(2000);
                System.out.println(a);
                return a;
            }
        }
    
        @Benchmark
        public static void testS() {
            try {
                Future<Integer> i = MQ_POOL.submit(new action());
                i.get();
            } catch (RejectedExecutionException e) {
                System.out.println("放弃" + e.getMessage());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String [] f) throws RunnerException {
            
            // jhm压力测试
            Options opt = new OptionsBuilder().include(MyThread.class.getSimpleName()).forks(1).warmupIterations(0)
                    .measurementIterations(1).build();
    
            new Runner(opt).run();
    
            // 自己的压力测试
            MyYali.start(40);
    
    
        }
    
        private static class MyYali implements Runnable {
    
            public static void start(int threadCount) {
    
                for(int i=0; i<threadCount; ++i) {
                    new Thread(new MyYali()).start();
                }
            }
    
            // 这个地方如果用1不会出错
            private int count = 2;
    
            @Override
            public void run() {
                for(int i=0; i<count; ++i) {
                    testS();
                }
            }
        }
    }
    

    循环次数 2          jhm              自己压测

    阻塞队列长度 36   多个放弃,响应时间28~19    1个放弃,相当稳定地每次出现在第4个打印“0”后

    阻塞队列长度 37   没有放弃,响应时间20        没有放弃

    循环次数 1        

    阻塞队列长度 36      /                 没有放弃 

    阻塞队列长度 37      /                没有放弃

      

    放弃Task java.util.concurrent.FutureTask@1339fcef rejected from java.util.concurrent.ThreadPoolExecutor@300fa78c[Running, pool size = 4, active threads = 4, queued tasks = 35, completed tasks = 14]

    所有根据现象推测,为什么36个线程就是出了拒绝,而且从手写的压测代码看,稳定的出现在第一批4个核心线程执行完,而且只出现一次

    40个投递线程并发投递,4个线程抢到优先执行权,36个线程塞入长度为36的阻塞队列

    第一个投递线程第一次循环执行完,但线程池还来不及将该坑位标志,并释放坑位

    第二个循环submit,发现核心4个坑和36个等待坑都满着,抛出放弃异常

    所以最佳实践就是,如果要求阻塞队列长度为n,实践层面将其设置为n+1

    底层为何有这种现象,要等全面了解线程池源码后来解析

  • 相关阅读:
    Union用法及说明:
    SQL用了Union后的排序问题
    10条PHP编程习惯助你找工作
    PHP性能分析工具xhprof的安装使用与注意事项
    11款数据分析工具(附体验网址)
    Linux下的库操作工具-nm、ar、ldd、ldconfig和ld.so
    ldd显示可执行模块的dependenc
    计算机图形学,三维框架设计
    dnat,snat
    百度识图API
  • 原文地址:https://www.cnblogs.com/silyvin/p/11875907.html
Copyright © 2020-2023  润新知