Java线程池一原理参数解释

2018-04-24  本文已影响0人  青果果

线程池

程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互
而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时
更应该考虑使用线程池

线程池里的每个线程代码结束后并不会死亡
而是再次回到线程池中成为空闲状态,等待下一个对象再来使用

JDK5之前,要手动实现线程池,从JDK 5开始,Java内置支持线程池

Executor和ExecutorService

Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池
而只是一个执行线程的工具


比较重要的几个类
public interface Executor {
    /**
     * Executes the given command at some time in the future.  The command
     * may execute in a new thread, in a pooled thread, or in the calling
     * thread, at the discretion of the {@code Executor} implementation.
     *
     * @param command the runnable task
     * @throws RejectedExecutionException if this task cannot be
     * accepted for execution
     * @throws NullPointerException if command is null
     */
    void execute(Runnable command);
}

真正的线程池接口是ExecutorService,定义了各种方法

public interface ExecutorService extends Executor {

    void shutdown();

    List<Runnable> shutdownNow();

    boolean isShutdown();

    boolean isTerminated();

    boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;

    <T> Future<T> submit(Callable<T> task);

    <T> Future<T> submit(Runnable task, T result);

    Future<?> submit(Runnable task);

    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;

    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

ExecutorService的子类

ThreadPoolExecutor的构造方法

构造线程池的基本参数

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

corePoolSize、maximumPoolSize、BlockingQueue之间的关系

所有的BlockingQueue都可用于传输和保持提交的任务。可以使用此队列与池大小进行交互:

corePoolSize一般不会设置的很大,会根据CPU核心数和需求场景来设置
其实线程池的配置主要在这三个参数了,他们之间是有相互关系的

看Demo:

class ThreadRunnable implements Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep(1000);//不加延时 可能出不来效果
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + ":正在执行");
    }
}

创建线程池并添加任务

       ExecutorService  pool = new ThreadPoolExecutor(
                4,
                10,
                60,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(128)
        );

        for (int i = 0; i < 30; i++) {
            pool.execute(new ThreadRunnable());
        }

结果:


image.png

如果将 new LinkedBlockingDeque<>(128)的128改为5
再看结果:


image.png

错误详情:

Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task ThreadRunnable@7ea987ac rejected from java.util.concurrent.ThreadPoolExecutor@12a3a380[Running, pool size = 10, active threads = 10, queued tasks = 5, completed tasks = 0]
    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
    at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
    at ThreadPoolDemo.main(ThreadPoolDemo.java:22)

那为什么会出现这样的情况呢?
首先看下线程池是如何工作的:
首先任务加入队列,创建线程,从任务队列获取任务并执行

Demo设置的核心线程数4,最大线程数10,任务总数为20

源码:

   public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

线程池排队策略

排队有三种通用策略:

上一篇下一篇

猜你喜欢

热点阅读