java 线程知识问答

简介

一个线程的核心线程数是4, 最大线程数是8, 有一个任务提交过来, 迅速执行王弼, 如果再来一个任务, 那么线程池是新建一个线程去执行还是会复用之前的线程?

参考链接

https://blog.csdn.net/hu10131013/article/details/105665232 (逻辑图片清晰)
https://www.cnblogs.com/jxxblogs/p/11655670.html (测试代码来源)

answer

根据线程创建的逻辑而言.

如果没有创建了4个核心线程, 会创建一个新线程来执行. 虽然第一个线程使用完毕了.

测试代码

import com.sun.xml.internal.ws.util.StringUtils;

import java.io.Console;
import java.util.concurrent.*;

/**
 * Created by lee on 2021/6/28.
 */
public class ThreadPoolLocal {
    public static void main(String[] args) throws InterruptedException {
        int size = 5;
        ThreadPoolExecutor es1 = new ThreadPoolExecutor(
                4, // corePoolSize
                8, // int maximumPoolSize
                1,// long keepAliveTime
                TimeUnit.DAYS, //   TimeUnit unit
                new LinkedBlockingQueue<>(10) // BlockingQueue<Runnable> workQueue
        );
        for(int i=0; i<size; i++){
            es1.execute(new DemoTask(i));

            System.out.println("poolSize: " + es1.getPoolSize());
            System.out.println("corePoolSize: " + es1.getCorePoolSize());
            System.out.println("maximumPoolSize:" + es1.getMaximumPoolSize());
            System.out.println("queue:" + es1.getQueue().size());
            System.out.println("completedTaskCount:" + es1.getCompletedTaskCount());
            System.out.println("largestPoolSize:" + es1.getLargestPoolSize());
            System.out.println("keepAliveTime:" + es1.getKeepAliveTime(TimeUnit.SECONDS));
            Thread.sleep(3000); // 沉睡3s在执行下一个任务. 上一个任务2s就执行完毕了, 但是因为没有达到核心线程数, 还是去创建了新的线程.

        }
        es1.shutdown();
    }
}

class DemoTask implements Runnable {
    private int taskNum;
    public DemoTask(int taskNum) {
        this.taskNum = taskNum;
    }

    @Override
    public void run() {
        System.out.println("正在执行" + taskNum);
        try {
            Thread.sleep(2000);
        }catch(InterruptedException ex) {
            ex.printStackTrace();
        }
        System.out.println("执行完毕" + taskNum);
    }
}

线程池和核心参数和拒绝策略有哪些?

线程池的构造函数有一些是默认的. 比如测试代码中使用的就是有部分默认的
完整的应该是如下


    /**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters and default thread factory.
     *
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * @param unit the time unit for the {@code keepAliveTime} argument
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * @param handler the handler to use when execution is blocked
     *        because the thread bounds and queue capacities are reached
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue}
     *         or {@code handler} is null
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }
     * @param handler the handler to use when execution is blocked
     *        because the thread bounds and queue capacities are reached // 当阻塞队列已经满了的时候, 我们应该使用哪些拒绝策略

handler 就是拒绝策略, 简单来说.
默认是会抛出异常, 将demo代码中的size 改成 100 可以看到抛出了一个异常.

1、AbortPolicy:直接抛出异常。
2、CallerRunsPolicy:只用调用者所在线程来运行任务。 -- 简单来说, 就是上述demo的main线程来运行任务.
3、DiscardOldestPolicy:丢弃队列里最老(引用文献使用最近,感觉有问题)的一个任务,并执行当前任务。
4、DiscardPolicy:不处理,丢弃掉。

简单理解:
如果很线程任务涌入的话, 直接奔溃报错.
主线程分配了任务, 我线程池接受不了, 拒绝, 你自己做吧.
新来的任务最重要, 旧的任务我就不做了.
直接丢弃. 不做了.

Hope is a good thing,maybe the best of things,and no good thing ever dies.----------- Andy Dufresne
原文地址:https://www.cnblogs.com/eat-too-much/p/14944356.html