JDK8线程池-Executors-ThreadPoolExecutor用法

前言

Executors工具类的用法与缺陷

1. 固定线程的线程池

    ExecutorService ex1 = Executors.newFixedThreadPool(5);
    for (int i=0;i<10;i++){
        ex1.execute(()-> System.out.println(Thread.currentThread().getName()));
    }

    ex1.shutdown();

缺陷:队列是无界队列

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

LinkedBlockingQueue默认是 Integer.MAX_VALUE容量,意味着如果任务足够多,可以存储Integer.MAX_VALUE的Runnable任务,普通服务器内存一定会溢出。

    public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }

    
    public LinkedBlockingQueue(int capacity) {
        if (capacity <= 0) throw new IllegalArgumentException();
        this.capacity = capacity;
        last = head = new Node<E>(null);
    }

2. 无限线程的线程池

    ExecutorService ex2 = Executors.newCachedThreadPool();
    for (int i=0;i<10;i++){
        ex2.execute(()-> System.out.println(Thread.currentThread().getName()));
    }

    ex2.shutdown();

缺陷:线程池的容量是Integer.MAX_VALUE

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

这里的SynchronousQueue只能存储一个任务,保证串行化要求。

线程的最大上线是Integer.MAX_VALUE结果是0x7fffffff,服务器根本支持不了这么多线程,内存和CPU不支持。很容易造成服务器宕机。

3. 单线程线程池

    ExecutorService ex3 = Executors.newSingleThreadExecutor();
    for (int i=0;i<10;i++){
        ex3.execute(()-> System.out.println(Thread.currentThread().getName()));
    }

    ex3.shutdown();

缺陷:无界队列,单线程无法发挥线程池的能力,很鸡肋

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

同样LinkedBlockingQueue,默认Integer.MAX_VALUE容量。

4. 线程池返回结果

上面的例子可以使用submit方法,可以接收线程的返回值。

    ExecutorService ex1 = Executors.newFixedThreadPool(5);
        List<Future<String>> list = new LinkedList<>();
        for (int i=0;i<10;i++){
            Future<String> future = ex1.submit((Callable) () -> Thread.currentThread().getName());
            list.add(future);
        }

        list.stream().forEach((s)-> {
            try {
                System.out.println(s.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        });

        ex1.shutdown();

5. 总结

由于以上方法的缺陷,在生产复杂的环境下,我们无法控制业务的提交,造成内存溢出,CPU 100%

一般不推荐使用Executors工具类,推荐直接使用ThreadPoolExecutor自己调参数

ThreadPoolExecutor参数的用途可以参考我的博客JDK8线程池-ThreadPoolExecutor参数

ThreadPoolExecutor的执行过程可以参考我的博客JDK8线程池-ThreadPoolExecutor源码解析

猜你喜欢

转载自blog.csdn.net/fenglllle/article/details/83478382