线程池知识

线程池

1.深入理解线程池

1.1 常用线程池体系结构

  • Executor:线程池顶级接口
  • ExecutorService:线程池次级接口
  • AbstractExecutorService:抽象类,运用模板犯法设计模式实现了一部分算法
  • ScheduledExecutorService:接口功能加强
  • ForkJoinPool:新型线程池类,基于工作窃取理论实现,运用于大任务拆小任务,任务无限多的场景
  • ThreadPoolExecutor:普通线程池类,包含最基本的一些线程池操作相关的方法
  • ScheduledThreadPoolExecutor:定时任务线程池类,用于实现定时任务相关功能
  • Executors: 线程池工具类,定义了一些快速实现线程池的方法

请添加图片描述

1.2 ExecutorService

扩展了 Executor的方法请添加图片描述

1.3 AbstractExecutorService

AbstractExecutorService:抽象类,运用模板方法设计模式实现了一部分算法

1.3.1 submit

提交

public Future<?> submit(Runnable task) {
    if (task == null) {
        throw new NullPointerException();
    } else {
        // newTaskFor 实际上是实例了一个 runable + future 对象,使其可以执行,也可以将结果返回
        RunnableFuture<Void> ftask = this.newTaskFor(task, (Object)null);
        // 后续调用execute
        this.execute(ftask);
        return ftask;
    }
}
1.3.2 invokeAny

只执行完成其中一个

具体实现是由 doInvokeAny实现
请添加图片描述

源码如下:

private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks, boolean timed, long nanos) throws InterruptedException, ExecutionException, TimeoutException {
    // 日常判空
    if (tasks == null) {
        throw new NullPointerException();
    } else {
        // 任务数
        int ntasks = tasks.size();
        if (ntasks == 0) {
            throw new IllegalArgumentException();
        } else {
            // 将任务放到一个数组中
            ArrayList<Future<T>> futures = new ArrayList(ntasks);
            // 生成一个 LinkedBlockingQueue 
            ExecutorCompletionService ecs = new ExecutorCompletionService(this);

            try {
                ExecutionException ee = null;
                // 计算超时时限 (如果使用invokeany(,时限))
                long deadline = timed ? System.nanoTime() + nanos : 0L;
                // 任务迭代器读取
                Iterator<? extends Callable<T>> it = tasks.iterator();
                // 将迭代器获取的任务放到LinkedBlokingQueue,并放到数组中
                futures.add(ecs.submit((Callable)it.next()));
                // 任务数--
                --ntasks;
                // 执行中/活动中的任务赋值为1
                int active = 1;

                while(true) {
                    // 将刚刚放到Queue中的任务拿出来
                    Future<T> f = ecs.poll();
                    // 如果完成队列中没有任务结束
                    if (f == null) {
                        // 还有任务需要做
                        if (ntasks > 0) {
                            // 这里如果任务一直不执行成功的话,就会一直往队列中放,直到所有任务都放进去,执行
                            // 任务数 -- 
                            --ntasks;
                            // 任务进队列
                            futures.add(ecs.submit((Callable)it.next()));
                            // 活动数 ++
                            ++active;
                        } else {
                            // 没有任务了
                            if (active == 0) {
                                // 活动中的任务也为0 
                                if (ee == null) {  
                                    ee = new ExecutionException();
                                }
 								// 抛出异常,因为能够进入这里,说明必定是有任务在执行的。但是此时活动中的任务为0
                                throw ee;
                            }
							// 设置了超时时限
                            if (timed) {
                                // 按照时限去取
                                f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
                                // 如果一个任务直接把所有时间都消耗了,那么就是超时了
                                if (f == null) {
                                    throw new TimeoutException();
                                }
								// 整体任务还剩多长时间
                                nanos = deadline - System.nanoTime();
                            } else {
                                // 没有设置超时时限,去看看有没有执行成功的消息,如果还是没有 则会一直循环
                                // 这里也能保证拿到的结果是只有一个任务产生的结果
                                f = ecs.take();
                            }
                        }
                    }
					// 说明已经有任务执行成功了
                    if (f != null) {
                        // 活动数减少
                        --active;

                        try {
                            // 获取任务执行结果
                            Object var14 = f.get();
                            return var14;
                        } catch (ExecutionException var19) {
                            ee = var19;
                        } catch (RuntimeException var20) {
                            ee = new ExecutionException(var20);
                        }
                    }
                }
            } finally {
                // 将其他任务取消
                cancelAll(futures);
            }
        }
    }
}
eg.
public class T_001_ThreadPoolExecutorDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        ArrayList<Callable<Integer>> callableArrayList = Lists.newArrayList(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                TimeHelper.sleep(15);
                return 1;
            }
        }, new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                TimeHelper.sleep(10);
                return 2;
            }
        });
        System.out.println(executorService.invokeAny(callableArrayList));
    }
}
结果如下

请添加图片描述

1.线程1 线程2 放到线程池中
2.线程1 执行
3.线程2 执行
3.线程2睡眠10S后任务结束,
4.此时会触发 cancel(线程1)
5.cancel(线程1) 会抛出Interrupted异常 
ExecutorCompletionService
public class ExecutorCompletionService<V> implements CompletionService<V>
    
public Future<V> submit(Runnable task, V result) {
        if (task == null) {
            throw new NullPointerException();
        } else {
            RunnableFuture<V> f = this.newTaskFor(task, result);\
            // 包装一下 Task
            this.executor.execute(new ExecutorCompletionService.QueueingFuture(f, this.completionQueue));
            return f;
        }
    }

// 装饰者模式
private static class QueueingFuture<V> extends FutureTask<Void> {
        private final Future<V> task;
        private final BlockingQueue<Future<V>> completionQueue;

        QueueingFuture(RunnableFuture<V> task, BlockingQueue<Future<V>> completionQueue) {
            super(task, (Object)null);
            this.task = task;
            this.completionQueue = completionQueue;
        }
		
    	// 任务执行完成会调用done
        protected void done() {
            this.completionQueue.add(this.task);
        }
    }
public interface CompletionService<V> {
    Future<V> submit(Callable<V> var1);

    Future<V> submit(Runnable var1, V var2);

    Future<V> take() throws InterruptedException;

    Future<V> poll();

    Future<V> poll(long var1, TimeUnit var3) throws InterruptedException;
}

1.3.3 invokeAll

源码如下:

public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
    // 日常判空
    if (tasks == null) {
        throw new NullPointerException();
    } else {
        ArrayList futures = new ArrayList(tasks.size());

        try {
            Iterator var3 = tasks.iterator();

            while(var3.hasNext()) {
                Callable<T> t = (Callable)var3.next();
                RunnableFuture<T> f = this.newTaskFor(t);
                futures.add(f);
                // 每个任务都执行
                this.execute(f);
            }

            int i = 0;

            for(int size = futures.size(); i < size; ++i) {
                Future<T> f = (Future)futures.get(i);
                if (!f.isDone()) {
                    try {
                        f.get();
                    } catch (ExecutionException | CancellationException var7) {
                    }
                }
            }
			// 将结果返回
            return futures;
        } catch (Throwable var8) {
            cancelAll(futures);
            throw var8;
        }
    }
}

1.4 Executors

线程池工具类,定义了一些快速实现线程池的方法

线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。说明:Executors各个方法的弊端:

1)newFixedThreadPool和newSingleThreadExecutor: 主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。

2)newCachedThreadPool和newScheduledThreadPool: 主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。

// 主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
}

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

// 线程最大数 为 Integer.MAX_VALUE
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, 2147483647, 60L, TimeUnit.SECONDS, new SynchronousQueue());
    }

 public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) {
        super(corePoolSize, 2147483647, 10L, TimeUnit.MILLISECONDS, new ScheduledThreadPoolExecutor.DelayedWorkQueue(), threadFactory);
    }

1.5 ThreadPoolExecutor

1.5.1 原理:

请添加图片描述

1.5.2 参数内容

请添加图片描述

public ThreadPoolExecutor(int corePoolSize, // 核心线程数 
                          int maximumPoolSize,  // 最大线程数
                          long keepAliveTime,  // 等待时间
                          TimeUnit unit,  // 时间单位
                          // BlockingQueue
						  // 没有任务执行的时候,会阻塞线程,如果有任务需要执行,则唤醒线程
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,  // 线程工厂
                          RejectedExecutionHandler handler // 处理策略
                         ) {
    this.ctl = new AtomicInteger(ctlOf(-536870912, 0));
    this.mainLock = new ReentrantLock();
    this.workers = new HashSet();
    this.termination = this.mainLock.newCondition();
    if (corePoolSize >= 0 && maximumPoolSize > 0 && maximumPoolSize >= corePoolSize && keepAliveTime >= 0L) {
        if (workQueue != null && threadFactory != null && handler != null) {
            this.corePoolSize = corePoolSize;
            this.maximumPoolSize = maximumPoolSize;
            this.workQueue = workQueue;
            this.keepAliveTime = unit.toNanos(keepAliveTime);
            this.threadFactory = threadFactory;
            this.handler = handler;
        } else {
            throw new NullPointerException();
        }
    } else {
        throw new IllegumentException();
    }
}
1.5.3 拒绝策略

AbortPolicy() 抛出reject异常 --默认
CallerRunsPolicy() 调用者执行
DiscardPolicy() 直接丢弃
DiscardOldestPolicy() 丢弃队列中最老的

public class T_002_ThreadPoolExecutorDemo {
    public static void main(String[] args) {
        int cps=1;
        int mps=2;
        int c = 5;
        int size = mps +  c;
        // 核心线程1, 临时线程数1 , 等待60
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(cps, mps, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(c));
        for (int i = 0; i < size; i++) {
            threadPoolExecutor.execute(()->{
                TimeHelper.sleep(10);
            });
        }
        // reject 异常
        threadPoolExecutor.execute(()->{
            TimeHelper.sleep(1);
        });
        System.out.println("wait");
    }
    
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(cps, mps, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(c), Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());
        for (int i = 0; i < size; i++) {
            threadPoolExecutor.execute(() -> {
                TimeHelper.sleep(10);
            });
        }
        // 调用者自己执行
        threadPoolExecutor.execute(() -> {
            TimeHelper.sleep(1);
        });
        System.out.println("wait");
}

自定义拒绝策略

public class T004_ThreadPool_MyRejectHandler {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(10,
                10,
                0L,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque(),
                Executors.defaultThreadFactory(),
                new RejectedExecutionHandler() {
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                        if (!executor.isShutdown()) {
                            System.out.println("满了 满了");
                        }
                    }
                }
        );
        
    }
}
1.5.4 ThreadPool的5种状态

RUNNING:接受新任务和进程队列任务
SHUTDOWN : 不接受新任务,但是会执行已经进队列的任务
STOP:不接受新任务也不接受已经进队列的任务,并打断正在执行中的任务
TIDYING:所有任务终止,待处理任务数量为0,线程转换为TIDYING,将会执行terminated钩子函数
TERMINATED:terminated 执行完成

RUNNING -> SHUTDOWN 调用shutdown()方法
RINNING/SHUTDOWN -> STOP 调用shutdownNow()方法
SHUTDOWN -> TIDYING:队列和线程池为空
STOP->TIDYING: 线程池为空
TIDYING -> TERMINATED :钩子函数terminated()执行完成

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ba8T8eUB-1627222831622)(多线程线程池.assets/image-20210725182107314.png)]

public class T003_ThreadPoolState {
    public static void main(String[] args) throws InterruptedException {
        //ExecutorService executorService = Executors.newFixedThreadPool(1);
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                1,
                1,
                0L,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingDeque<>(),
                new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                        Thread thread = new Thread(r);
                        thread.setDaemon(true);
                        return thread;
                    }
                });

        threadPoolExecutor.submit(()->{
            System.out.println("hello");
            TimeHelper.sleep(10);
            System.out.println("exit");
        });

		// 如果执行 shutdown 会打印 hello exit
        threadPoolExecutor.shutdown();
        // 如果执行 shutdownNow ,则会抛出打断的异常
        threadPoolExecutor.shutdownNow();
        threadPoolExecutor.awaitTermination(1, TimeUnit.MINUTES);
    }
}
1.5.5 源码分析
1.5.5.1 execute源码
public void execute(Runnable command) {
    	// 日常判空
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
        int c = ctl.get();
    	// 当前执行线程数 < 核心线程
        if (workerCountOf(c) < corePoolSize) {
            // 添加核心线程执行任务
            if (addWorker(command, true))
                return;
            // 重新获取下
            c = ctl.get();
        }
        // 当前线程池的状态 为RUNNING 并且能够成功入队
        if (isRunning(c) && workQueue.offer(command)) {
            // 再重新获取
            int recheck = ctl.get();
            // 线程池 状态不为 RUNNING , 移出任务队列成功
            if (! isRunning(recheck) && remove(command))
                // 拒绝
                reject(command);
            // 资源全部释放了
            else if (workerCountOf(recheck) == 0)
                // 添加一个非核心线程执行任务
                addWorker(null, false);
        }
    	// 无法添加非核心线程数(到达了最大线程数)
        else if (!addWorker(command, false))
            // 拒绝
            reject(command);
    }
private boolean addWorker(Runnable firstTask, boolean core) {
    retry: // 用于goto
    for (;;) {
    	// 快照
        int c = ctl.get();
        // 运行时状态
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        /** return true
        	1.线程池正常执行 RUNNING
        	2.线程池SHUTDOWN 提交的任务不是新任务(队列中的任务) 工作队列不为空
        */
        // 线程池关闭
        if (rs >= SHUTDOWN && 
            ! (
                // SHUTDOWN 不可接受外部任务,但是需要执行内部队列
                rs == SHUTDOWN &&
               // 该任务是不是新提交任务
               firstTask == null &&
               // 工作队列是否为空
               ! workQueue.isEmpty()))
            return false; // 不添加worker了
        
        for (;;) {
            // 工作线程数量
            int wc = workerCountOf(c);
            // 工作线程数量 >= 最大容忍的量
            if (wc >= CAPACITY ||
                // 添加的为核心线程数 还是 非核心线程数
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false; // 不允许添加了
            // 能够添加
            // CAS 的增加 任务线程数,如果增加成功 那么就可以跳出循环 接下去走
            if (compareAndIncrementWorkerCount(c))
                break retry; // 
            // 添加失败了 要重新处理 因为出现了线程竞争
            c = ctl.get();  // Re-read ctl
            // 如果当前线程池被关闭了,那么就没必要在这边了
            if (runStateOf(c) != rs)
                continue retry;
            // else CAS failed due to workerCount change; retry inner loop
        }
    }

    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        // 创建了一个新的worker
        w = new Worker(firstTask);
        // 取出线程
        final Thread t = w.thread;
        if (t != null) {
            //
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            // 会有多线程
            try {
                // Recheck while holding lock.
                // Back out on ThreadFactory failure or if
                // shut down before lock acquired.
                int rs = runStateOf(ctl.get());

                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    if (t.isAlive()) // precheck that t is startable
                        throw new IllegalThreadStateException();
                  //private final HashSet<Worker> workers = new HashSet<Worker>();
                    workers.add(w);
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                // 启动线程
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            // 启动失败 会将执行任务数 减去
            addWorkerFailed(w);
    }
    return workerStarted;
}
Worker:
        /** Thread this worker is running in.  Null if factory fails. */
        final Thread thread;
        /** Initial task to run.  Possibly null. */
        Runnable firstTask;
        /** Per-thread task counter */
        volatile long completedTasks;
        
        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker 防止在runWoker之前被中断
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }
final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        // task = getTask() 不会抛出异常
        while (task != null || (task = getTask()) != null) {
            w.lock();
            // If pool is stopping, ensure thread is interrupted;
            // if not, ensure thread is not interrupted.  This
            // requires a recheck in second case to deal with
            // shutdownNow race while clearing interrupt
            // 线程池关闭 STOP TIDYING TERMINATED
            if ( (runStateAtLeast(ctl.get(), STOP) ||
                  // RUNNING SHUTDOWN 过程中 线程打断 
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                // 线程是否被中断过(清除标记位)
                !wt.isInterrupted())
                // 中断线程
                wt.interrupt();
            try {
                // 执行前,执行后
                beforeExecute(wt, task); // 发生异常 completedAbruptly = true
                Throwable thrown = null;
                try {
                    task.run();
                } catch (RuntimeException x) {
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    // 线程池异常如何抛出 
                    afterExecute(task, thrown); // 发生异常 completedAbruptly = true
                }
            } finally {
                task = null;
                // 完成任务数++
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        // 工作线程的死亡 是由于用户异常导致的
        processWorkerExit(w, completedAbruptly);
    }
}
private void processWorkerExit(Worker w, boolean completedAbruptly) {
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount(); // 减少工作线程数

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            completedTaskCount += w.completedTasks;
            // hashSet中移除 
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }

        tryTerminate();

        int c = ctl.get();
    	// SHUTDOWN RUNNING
        if (runStateLessThan(c, STOP)) {
            // 是否用户线程导致的
            if (!completedAbruptly) {
                // 保证最起码有一个线程在执行
                // 不是用户线程导致的
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                // 队列不为空
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                // 如果工作线程 < 1 那么就会 新起线程
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            // 用户异常造成的会新起一个非核心的任务线程
            addWorker(null, false);
        }
    }

2. 关于线程池的常见问题

2.1 常见的线程池有哪些

2.1.1 newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
    // 固定线程数的线程数,核心线程数 = 最大线程数
    // 缺点:1.如果线程池中没有任务执行,核心线程不会释放资源,占用一定的系统资源
    //		2.采用了LinkedBlockingQueue ,虽然有最大限制为 Integer.MAX_VALUE,也相当于是一个无界的	队列,容易造成OOM
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
2.1.2 newCachedThreadPool
public static ExecutorService newCachedThreadPool() {
    // 核心线程数为0 ,最大线程数为 Integer.MAX_VALUE
    // 这样做有个优点 就是,如果工作线程超过60S 没有任务执行,那么它会自动终止,终止后如果有新的任务,会重新创建新的进程,节省了资源
    // 缺点: 可以创建很多个线程,可能会造成OOM
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
2.1.3 newScheduleThreadPool
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
// scheduleThreadPoolExecutor 继承了 ThreadPoolExecutor
public ScheduledThreadPoolExecutor(int corePoolSize) {
    	// 核心线程数为定长,最大线程数 为 Integer.MAX_VALUE
    	// 缺点也很明显,可以创建很多线程,可能造成OOM
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
2.1.4 newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
    // 固定核心线程数为1 最大线程数为1
    // 优点:单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的
    // 缺点:无界队列 可能会造成OOM
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
2.1.5 newWorkStealingPool
public static ExecutorService newWorkStealingPool() {
    // 使用的是ForkJoin
    return new ForkJoinPool
        (Runtime.getRuntime().availableProcessors(),
         ForkJoinPool.defaultForkJoinWorkerThreadFactory,
         null, true);
}
// ForkJoinPool 主要用于实现“分而治之”的算法,特别是分治之后递归调用的函数,例如 quick sort 等。
总结:

常见的有:

​ 定长的(newFixedThreadPool, newSingleThreadExecutor)这种一般都由于使用了LinkedBlockingQueue 这种无界队列,可能会造成OOM

​ 特殊功能:newScheduleThreadPool 调度线程池

​ newCachedThreadPool 缓存线程池

​ 缺点是 最大线程数为 Integer.MAX_VALUE 也可能造成OOM

2.2 阿里巴巴Java开发手册为什么不允许使用Executors的默认实现

通过2.1 以及 1.4 中的描述已经可以解决该问题

线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。说明:Executors各个方法的弊端:

1)newFixedThreadPool和newSingleThreadExecutor: 主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。

2)newCachedThreadPool和newScheduledThreadPool: 主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。

2.3 自定义线程池(自定义线程池参数、参数设置的依据)

线程池参数: 如 1.5.2 描述一致

corepoolsize: 核心线程数 -> 不会释放资源

maxpoolsize: 最大线程数 -> 可以创建的最大线程数

keepalivetime: 线程留存时间 -> 临时线程执行完成后,可以待多长时间(因为临时线程是需要释放资源的)

TIMEUNIT : 留存时间单位

workQueue:工作队列

ThreadFactory:线程工厂

rejectHandler: 拒绝策略

2.4 自定义线程池完了,描述下这个线程池的工作流程

可以参考1.5.5.1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gnmvodN8-1627222831622)(多线程线程池.assets/image-20210725214402479.png)]

队列中的线程是什么时候被调用的?

其实 在 执行 t.start() 会调用 RunWork.run()

具体源码可以参照 1.5.5.1中的 runWorker方法

执行时 会判断 队列中是否为空 task = getTask(),此时就会把队列中的数据拿出来执行了

2.5 如果线程池满了会怎么办(线程池的拒绝策略)

拒绝抛出异常(默认策略)

静默拒绝:

给调用线程执行:占用资源

丢弃队列中最老的:

2.6 常见的工作队列有哪些

参考2.1

LinkedBlockingQueue 无界队列,容易OOM

SynchronousQueue : 缓存用,内部不存储数据

public SynchronousQueue(boolean fair) {
    // 直接new 了一个 transferqueue
    transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
}
TransferQueue() {
    QNode h = new QNode(null, false); // initialize to dummy node.
    head = h;
    tail = h;
}
SynchronousQueue 也是一个队列来的,但它的特别之处在于它内部没有容器,一个生产线程,当它生产产品(即put的时候),如果当前没有人想要消费产品(即当前没有线程执行take),此生产线程必须阻塞,等待一个消费线程调用take操作,take操作将会唤醒该生产线程,同时消费线程会获取生产线程的产品(即数据传递),这样的一个过程称为一次配对过程(当然也可以先take后put,原理是一样的)。
————————————————
原文链接:https://blog.csdn.net/yanyan19880509/article/details/52562039

DelayedWorkQueue : 按照时间进行排序,由于定时调度

ArrayBlokingQueue: 指定大小

PriiriBlockingQueue: 优先级队列

LinkedTransferQueue:implements TransferQueue 预占模式

LinkedTransferQueue是ConcurrentLinkedQueue、SynchronousQueue(公平模式下转交元素)、LinkedBlockingQueue(阻塞Queue的基本方法)的超集
————————————————
原文链接:https://blog.csdn.net/qq_38293564/article/details/80593821

2.7 线程池抛出异常的方式

run方法中trycatch
重写 afterExecute()
线程工厂 ,uncaughtException
future.get 获取异常

2.8 一个线程池中的线程异常了,那么线程池会怎么处理这个线程?

源码可以参照1.5.5.1 execute源码部分

如果是execute,我们可以看到异常输出

如果是submit,我们是看不到异常的,可以调用Future.get()方法捕获异常

线程异常不会影响到线程池中其他线程的正常执行

线程池会把这个线程移除,并创建一个新的线程放到线程池中(因为异常后,会在workset中把这个worker删掉 workers.remove(w);,然后再新增一个非核心线程 addWorker(null, false))

2.9 线程池的几种状态

详见1.5.4

RUNNING/SHUTDOWN/STOP/TDIYING/TERMINATED

RUNNING 可以通过shutdown() 转为 SHUTDOWN

(RUNNING/SHUTDOWN) 可以通过shutdownnow() 转为 STOP

SHUTDOWN 状态下 如果队列中任务数为0 ,工作线程也为0 会转为 TDIYING

STOP状态下 如果工作线程数为0 转为 TDYING

TDYING 会通过 terminated() 转为 TERMINATED

2.10 线程的几种状态

详细可以参考下 我的另外一篇文章 https://blog.csdn.net/tiancaideshaonian/article/details/118886497

NEW: 线程刚刚创建

RUNABLE(READY/RUNNING)

WAITTING:等待唤醒

TIME_WAITTING:间隔时间后自动唤醒

BLOCKED:被阻塞,等待锁

TERMINATED: 进程结束

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值