JAVA线程池分析实现

news2024/11/19 19:42:07

1、定义线程池

/**
     * 使用给定的初始参数创建新的 ThreadPoolExecutor对象,就创建了一个线程池
     * @param corePoolSize - 要保留在池中的线程数,即使它们处于空闲状态,若果allowCoreThreadTimeOut设置为ture,那么核心线程在keepAliveTime之后也会被回收
     * @param maximumPoolSize – 池中允许的最大线程数
     * @param keepAliveTime – 当线程数大于核心时,这是多余的空闲线程在终止之前等待新任务的最长时间,如果为0,表示不回收
     * @param unit – keepAliveTime 参数的时间单位
     * @param workQueue – 用于在执行任务之前保存任务的队列。此队列将仅保存由execute方法提交的可运行任务。
     * @param threadFactory – 执行程序创建新的线程处理程序时使用的工厂,可以自定义线程名称,用于排错
     * @param handler – 由于达到线程边界和队列容量而被阻止执行时使用的处理程序ThreadPoolExecutor定义了四种拒绝策略,可以通过实现RejectedExecutionHandler接口自定义拒绝侧率
     *                CallerRunsPolicy:如果线程池是RUNNING状态,直接调用run方法执行,不用线程池调用服务,否则丢弃任务
     *                AbortPolicy:抛出异常,线程池默认的拒绝策略
     *                DiscardPolicy:直接丢弃任务
     *                DiscardOldestPolicy:如果线程池是RUNNING状态,移除队列头部的任务(下一个任务不在执行),直接用线程池执行当前提交的任务,等于把当前任务替换了快要执行的下一个任务
     *                //自定义拒绝策略,如:假如不能丢弃任务,我们也不能无限制的往队列里面添加任务,容易内存不足报错,所以我们可以重新把任务一直往队列里面放,并且发出通知,不要产生新任务,另外一个地方定时检查线程池大小,发出通知可以产生新任务
     *                (r, e)->{
     *                     e.getQueue().put(r);  
     *                }
     * @Throws: 
     *            IllegalArgumentException – 非法参数异常 – 如果以下情况之一成立:corePoolSize < 0 keepAliveTime < 0 maximumPoolSize <= 0 maximumPoolSize < corePoolSize
     *            NullPointerException – if workQueue or threadFactory or handler is null
     **/
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
                maximumPoolSize <= 0 ||
                maximumPoolSize < corePoolSize ||
                keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

线程池自定义的4种拒绝策略,通过new ThreadPoolExecutor.AbortPolicy()就可以使用了
在这里插入图片描述

 public static class CallerRunsPolicy implements RejectedExecutionHandler {
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                //判断线程池是不是RUNNING
                r.run();
                //直接调用run方法
            }
        }
    }

    public static class AbortPolicy implements RejectedExecutionHandler {
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                    " rejected from " +
                    e.toString());
            //抛异常
        }
    }

    public static class DiscardPolicy implements RejectedExecutionHandler {
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            //不做任何事,任务丢弃
        }
    }

    public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                //判断线程池是不是RUNNING
                e.getQueue().poll();
                //移除头部的任务
                e.execute(r);
                //直接用线程池执行当前方法,就是替换下方法
            }
        }
    }

线程池的五种状态
RUNNING:运行状态
SHUTDOWN:线程池关闭,不在接收新任务,但线程池队列中的任务还是会执行完成
STOP:线程池停止,不接受新任务,且尝试终止线程池队列汇总的任务
TIDYING:线程池队列中所有的任务已经完成
TERMINATED:线程池状态为终止

//存储了线程池状态和工作线程数量,CAS自旋设置
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

2、继承ThreadPoolExecutor可以实现自己的线程池方案,可以重写下面几个保护方法,也可以覆盖父类的public方法,从而实现自己的线程池逻辑,也可以直接继承AbstractExecutorService抽象方法实现

    /**
     * GC回收,
     *
     * @param t
     * @param r
     */    
    protected void finalize() {
    	SecurityManager sm = System.getSecurityManager();
        if (sm == null || acc == null) {
        	//校验能不能终止线程,CAS设置线程池状态为SHUTDOWN,终止所有的线程,尝试终止线程池
            shutdown();
        } else {
            PrivilegedAction<Void> pa = () -> { shutdown(); return null; };
            AccessController.doPrivileged(pa, acc);
        }
    }

    /**
     * 线程执行开始前
     *
     * @param t
     * @param r
     */
    protected void beforeExecute(Thread t, Runnable r) {
    }

    /**
     * 线程执行完成后
     *
     * @param t
     * @param r
     */
    protected void afterExecute(Runnable r, Throwable t) {
    }

    /**
     * 线程池终止方法(在线程池等待队列为空,但线程池状态不是TERMINAL之前)
     */
    protected void terminated() {
    }

ScheduledThreadPoolExecutor就是继承了ThreadPoolExecutor并且实现了ScheduledExecutorService接口实现定时器功能

3、线程池的执行过程

3.1、提交任务

一般都是线程池的execute和submit方法

 public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        //封装一个又返回值的任务对象
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

什么时候线程池会执行拒绝策略:

  1. 线程池从RUNNING && 线程池队列未满,但任务添加进入线程池后,线程池状态变为非RUNING;
  2. 线程池不是RUNNING或者线程池队列已满,尝试添加任务执行(主要是能不能新建线程执行)失败;
 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)
            	//如果线程池是运行状态,并且工作线程个数为0,直接添加任务,这里面是执行任务的真正逻辑
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
        	//如果线程池状态非RUNNING || 队列线程池已满,那就尝试添加任务,如果不成功,调用线程池实现的拒绝策略
            reject(command);
    }

真正开始执行任务(执行线程,都需要执行当前方法)

线程池在SHUTDOWN状态之后是不是不能执行任务了
线程池在非RUNNING状态不能提交任务到线程池队列,但在SHUTODWN状态下,如果线程池队列不为空,可以继续执行线程池队列中的任务,直到线程池队列状态为空,才跳出循环

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        //循环
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
            //线程池状态不是RUNNING获取SHUTDOWN && (SHUTDOWN && 当前正在执行的任务为空 && 线程池队列里面不为空)->线程池不是RUNNING || 线程池是SHUTDOWN,但正在执行的线程不为NULL || 线程池队列里面存在任务
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                //添加任务失败   
                return false;
            for (;;) {
                int wc = workerCountOf(c);
                //线程池中的工作线程大于等于最大值 || (大于核心线程 || 最大线程数,根据入参是true还是false判断),返回false 
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    //添加任务失败
                    return false;
                //CAS增加一个worker,增加成功,退出循环跳到retry:,往下执行
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                //如果没有设置成功    
                c = ctl.get();  // Re-read ctl
                //线程状态以改变,继续循环,重新执行for循环
                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重写了toString方法,Worker对象实现了Runnable接口,并且创建线程时把this(当前worker对象作为Runnable放入了Thread,当t.start时就是执行worker对象的run方法)
            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());
					//线程池状态RUNNING 或者 SHUTDOWN && 堆首任务不存在
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        //如果线程已经执行,抛出异常	
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        //把新的任务加入到workers里面,workers就是个Set,如果toString方法相同,覆盖    
                        workers.add(w);
                        //获取当前工作组个数,如果大于最大值,更新最大值
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        //新增工作成功    
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                	//新增成功,开始执行任务t为Worker绑定的工作线程,Worker的工作线程传入的是它自己,也就是启用调用的是Worker的run方法
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

Worker的构造方法方法

Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            //堆首任务最先执行,ScheduledThreadPoolExecutor.ScheduledFutureTask类型
            this.firstTask = firstTask;
            //获取到Bean工厂就是ThreadPoolTaskScheduler对象,CustomizableThreadFactory->CustomizableThreadCreator创建线程,并且传入this(当前worker对象,需要实现Runnable接口)
            this.thread = getThreadFactory().newThread(this);
        }

Worker的toString方法

  public String toString() {
        long ncompleted;
        int nworkers, nactive;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            ncompleted = completedTaskCount;
            nactive = 0;
            nworkers = workers.size();
            for (Worker w : workers) {
                ncompleted += w.completedTasks;
                if (w.isLocked())
                    ++nactive;
            }
        } finally {
            mainLock.unlock();
        }
        int c = ctl.get();
        String rs = (runStateLessThan(c, SHUTDOWN) ? "Running" :
                     (runStateAtLeast(c, TERMINATED) ? "Terminated" :
                      "Shutting down"));
         //线程池状态,工作线程个数,未激活的线程个数,队列长度,未完成的任务数量             
        return super.toString() +
            "[" + rs +
            ", pool size = " + nworkers +
            ", active threads = " + nactive +
            ", queued tasks = " + workQueue.size() +
            ", completed tasks = " + ncompleted +
            "]";
    }

执行Worker对象的run方法,如果线程池状态为STOP,任务是否执行
当前worker线程在执行之前,会判断线程池状态是否是STOP,如果是,则终止线程

public void run() {
    runWorker(this);
}
final void runWorker(ThreadPoolExecutor.Worker w) {
   Thread wt = Thread.currentThread();
   Runnable task = w.firstTask;
   //防止任务重复执行
   w.firstTask = null;
   w.unlock(); // allow interrupts
   boolean completedAbruptly = true;
    try {
         while (task != null || (task = getTask()) != null) {
                w.lock();
				//如果线程池状态是STOP,终止线程	
                if ((runStateAtLeast(ctl.get(), STOP) ||
                        (Thread.interrupted() &&
                                runStateAtLeast(ctl.get(), STOP))) &&
                        !wt.isInterrupted())
                    wt.interrupt();
                try {
                    //执行当前任务之前做预处理,空方法,子类可以实现
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                    	//此处实现的是addWorker传入的Runnable,,一般线程为用户提交的Runnable,定时器调度线程是ScheduledFutureTask类,调用它的run方法
                        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);
                    }
                } finally {
                	//回收任务,并用于跳出循环,线程池任务完成+1
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
}

getTask()获取线程的方法

  1. 线程池RUNNING或者SHUTDOWN && 线程池队列不为空,则阻塞线程池
  2. 如果需要回收线程池allowCoreThreadTimeOut 为true或者活动线程>核心线程,但如果keepAliveTime<=0,直接返回NULL任务,会跳出循环;
  3. take阻塞线程队列,等待队列中存在新的任务唤醒;
private Runnable getTask() {
    boolean timedOut = false; // Did the last poll() time out?

    for (;;) {
       int c = ctl.get();
       int rs = runStateOf(c);

       // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
        	 //线程池不为RUNNING/或者是SHUTDOWN && 线程池为空,返回执行任务为NULL
             decrementWorkerCount();
             return null;
       }

            int wc = workerCountOf(c);

            // Are workers subject to culling?
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
			//允许回收核心线程 || 当前执行的线程个数大于核心线程
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                //如果大于最大线程,并且可以回收
                if (compareAndDecrementWorkerCount(c))
                	//减少一个Worker数量成功,返回run,否者继续循环等待线程回收
                    return null;
                continue;
            }

            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                //如果线程对象可以回收,使用poll等待回收时间,如果不能回收,使用take()阻塞线程池    
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
}
 public E poll(long timeout, TimeUnit unit) throws InterruptedException {
        E x = null;
        int c = -1;
        long nanos = unit.toNanos(timeout);
        final AtomicInteger count = this.count;
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lockInterruptibly();
        try {
            while (count.get() == 0) {
                if (nanos <= 0)
                    return null;
                //阻塞时间    
                nanos = notEmpty.awaitNanos(nanos);
            }
            x = dequeue();
            //获取队列头部信息
            c = count.getAndDecrement();
            if (c > 1)
            	//如果队列大于值在查询之前>1,表示队列中现在至少存在2个任务未执行,需要唤醒别的的等待获取任务的线程,每次唤醒一个线程,最后会根据存在的任务,线程池提交的阻塞任务都会被唤醒
                notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
        if (c == capacity)
            signalNotFull();
        return x;
    }
public E take() throws InterruptedException {
        E x;
        int c = -1;
        final AtomicInteger count = this.count;
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lockInterruptibly();
        try {
            while (count.get() == 0) {
            	//获取任务为空,阻塞线程,等待唤醒
                notEmpty.await();
            }
            x = dequeue();
            c = count.getAndDecrement();
            if (c > 1)
            	//如果队列大于值在查询之前>1,表示队列中现在至少存在2个任务未执行,需要唤醒别的的等待获取任务的线程,每次唤醒一个线程,最后会根据存在的任务,线程池提交的阻塞任务都会被唤醒
                notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
        if (c == capacity)
            signalNotFull();
        return x;
    }

任务执行完成,更新线程池状态,尝试终止线程池,回收线程资源

线程回收,线程池可能保存的最小线程,存在四种情况

  1. 如果allowCoreThreadTimeOut=false,最小线程等于核心线程;
  2. 如果allowCoreThreadTimeOut=true,并且线程池队列不为空,那么最小线程数量为1;
  3. 如果allowCoreThreadTimeOut=true,并且线程池队列为空,那么最小线程数为0;
  4. 如果当前工作线程>=上面存在的三种情况获得的最小线程数,那无需回收,否则回收线程;
private void processWorkerExit(Worker w, boolean completedAbruptly) {
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
        	//如果任务执行失败,抛异常等,任务执行完成-1
            decrementWorkerCount();
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
        	//更新执行完成任务数量
            completedTaskCount += w.completedTasks;
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }
		//尝试终止回收线程
        tryTerminate();

        int c = ctl.get();
        if (runStateLessThan(c, STOP)) {
        	// 如果状态是RUNNING或者SHUTDOWN
            if (!completedAbruptly) {
            	//任务执行正常完成,默认false,如果设置为true,那最小线程就为0,否者为核心线程数量
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && ! workQueue.isEmpty())
                	//如果核心线程
                    min = 1;
                if (workerCountOf(c) >= min)
                	//如果工作线程大于等于最小线程,直接返回,无需回收
                    return; // replacement not needed
            }
            //因为新增Running为空,worker新增失败,执行addWorker的addWorkerFailed方法,回收线程
            addWorker(null, false);
        }
    }

addWorkerFailed回收资源

 private void addWorkerFailed(Worker w) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (w != null)
                //worker不为空,移除worker
                workers.remove(w);
             //工作worker减少1   
            decrementWorkerCount();
            //尝试终止线程,回收资源
            tryTerminate();
        } finally {
            mainLock.unlock();
        }
    }

线程池执行remove方法,尝试回收线程资源

 final void tryTerminate() {
 		//没有退出条件的循环
        for (;;) {
        	//ctl存储的是线程池状态和工作线程个数
            int c = ctl.get();
            //线程状态 RUNNING||(TIDYING || TERMINATED)||(SHUTDOWN && 线程队列不为空),直接返回
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
                return;
            //线程执行任务不为0,但线程池状态只能为STOP   
            if (workerCountOf(c) != 0) { // Eligible to terminate	
            	//终端线程,回收资源,回收一个之后,下次执行到这里,状态还是STOP,worker还是不为0 ,又终止一个,直到都终止完成,之后对不是终止状态的线程池终止
                interruptIdleWorkers(ONLY_ONE);
                return;
            }
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
            	//如果线程状态为TIDYING
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        //终止线程,空方法,子类可以实现从TIDYING状态变为TERMINATED状态之前做一定逻辑判断
                        terminated();
                    } finally {
                    	//设置线程池状态为终止
                        ctl.set(ctlOf(TERMINATED, 0));
                        //唤醒所有的终止任务,根据链表,通过unpark一个一个暂停线程。
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }

终端Worker线程,回收Worker线程

  private void interruptIdleWorkers(boolean onlyOne) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (Worker w : workers) {
            	//获取所有活动的线程对象
                Thread t = w.thread;
                if (!t.isInterrupted() && w.tryLock()) {
                    try {
                    	//中断线程
                        t.interrupt();
                    } catch (SecurityException ignore) {
                    } finally {
                        w.unlock();
                    }
                }
                //终端一个后跳出循环
                if (onlyOne)
                    break;
            }
        } finally {
            mainLock.unlock();
        }
    }
public boolean cancel(boolean mayInterruptIfRunning) {
    boolean cancelled = super.cancel(mayInterruptIfRunning);
    if (cancelled && removeOnCancel && heapIndex >= 0)
    		//终止成功,移除任务
                remove(this);
    return cancelled;
}
public boolean cancel(boolean mayInterruptIfRunning) {
		//如果状态不是新 || 线程状态不能设置为CANCELLED,返回false,不能中断
        if (!(state == NEW &&
              UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
                  mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
            return false;
        try {    // in case call to interrupt throws exception
            if (mayInterruptIfRunning) {
                try {
                    Thread t = runner;
                    if (t != null)
                    	//中断线程
                        t.interrupt();
                } finally { // final state
                	//设置线程状态为中断
                    UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
                }
            }
        } finally {
        	//回收线程资源
            finishCompletion();
        }
        return true;
    }
  private void finishCompletion() {
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) {
            //循环队列节点
            if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
                for (;;) {
                	//当前节点循环
                    Thread t = q.thread;
                    if (t != null) {
                        q.thread = null;
                        //终止线程
                        LockSupport.unpark(t);
                    }
                    //获取当前节点的下游节点,如果为空,表示已当前节点作为初始节点的下游节点都已经被终止了
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    //下一个worker节点为空,解绑worker和线程池关系,GC能正常回收    
                    q.next = null; // unlink to help gc
                    //把它的下游节点设置为头部节点,循环上终止,移动节点任务
                    q = next;
                }
                break;
            }
        }
		//空方法,子类可以实现,比如判断线程是否都已回收,worker已经未0等等
        done();

        callable = null;        // to reduce footprint
    }

4、Spring提供的4种线程池,阿里云一般推荐自定义线程池,就是new ThreadPoolExecutor

Executors类通过静态方法定义了5种线程池

  1. 固定线程个数的线程池,核心线程=最大线程=入参
public static ExecutorService newFixedThreadPool(int nThreads) {
     return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
}
  1. 单线程线程池,类似固定大小,只是线程大小为1
public static ExecutorService newSingleThreadExecutor() {
     return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
}
  1. 缓存线程池,核心线程为0,默认缓存60s,就会回收不用的线程
public static ExecutorService newCachedThreadPool() {
     return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
}
  1. 单线程定时调度线程池,能执行定时任务的单线程线程池
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
     return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
}
  1. 设置核心线程个数的定时调度线程池
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
     return new ScheduledThreadPoolExecutor(corePoolSize);
}
  1. 传入自定义的线程池
public static ExecutorService unconfigurableExecutorService(ExecutorService executor) {
     if (executor == null)
         throw new NullPointerException();
     return new DelegatedExecutorService(executor);
}
  1. 传入自定义的定时任务线程池
public static ScheduledExecutorService unconfigurableScheduledExecutorService(ScheduledExecutorService executor) {
     if (executor == null)
          throw new NullPointerException();
     return new DelegatedScheduledExecutorService(executor);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/726407.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

整理——xilinx FPGA 在线升级

一&#xff1a;xilinx FPGA 在线升级方案&#xff1a;&#xff08;系统搭建&#xff1a;MicroBlaze软核处理器&#xff0c;uart控制器&#xff0c;Axi-lite-user用户通信接口&#xff0c;MIG DDR3控制器&#xff0c;中断控制器等&#xff0c;以太网控制器&#xff09; 1.跑一个…

C#开发的OpenRA游戏之建造物品的窗口10

C#开发的OpenRA游戏之建造物品的窗口10 前面已经分析完成建造物品的过程,从物品进入队列,直到物品按时间进行生产完成。那么生产完成之后,又是怎么样放置到游戏的地图里面的呢?本文就来分析这个问题。 前面可以看到,当物品建造完成时,会在右边的面板上显示建造完成: 在…

类 模板 已经声明为非类 模板

类 模板 已经声明为非类 模板 解决方案 原因是在当前包下&#xff0c;已经定义了AA类 解决方案 更改模板类AA的类名

爬虫入门05——requests中的post请求

爬虫入门05——requests中的post请求 以百度翻译为例&#xff0c;我们如何输入内容后获取翻译后的结果呢 打开百度翻译的界面 右键单击后选择检查 点击网络 在翻译的框内输入内容&#xff0c;就以输入“你好”为例&#xff0c; 点击sug&#xff0c;点击标头&#xff0c…

Linux 文件系统

文章目录 一、设备专用文件&#xff08;设备文件&#xff09;设备 ID 二、磁盘与分区1. 磁盘驱动器2. 磁盘分区 三、文件系统四、i-nodeext2 中的 i-node 与数据块指针 五、虚拟文件系统&#xff08;VFS&#xff09;六、日志文件系统七、单根目录层级与挂载点 一、设备专用文件…

aidl原理

aidl 流程 为了方便理解&#xff0c;先将binder看做是一个黑盒子 aidl的流程图如下 demo连接添加链接描述 Androidstudio 会帮我们生成emotionAidlService&#xff0c;具体目录在n\build\generated\aidl_source_output_dir\debug\out\com\example\emotion\emotionAidlServic…

swiftUI和swift的区别

概述 SwiftUI是苹果公司推出的一种用于构建iOS、macOS、watchOS和tvOS应用程序界面的框架。它是基于Swift编程语言开发的&#xff0c;旨在简化UI开发过程并提供实时预览功能&#xff0c;使开发人员可以更快地构建出漂亮的应用程序界面。 Swift是苹果公司推出的一种面向对象的…

【QT】混合UI设计

虽然利用Designer和代码的设计方式都可以开发GUI&#xff0c;但是毫无疑问的是最有效的开发方式是利用两者进行混合开发。 下面这个实验例子来自《QT5.9 C开发指南》&#xff0c;我做了小部分修改&#xff0c;最终效果是这样&#xff1a; 图标导入 这次我们要开发的是一个有工…

AprilTag码估算平面法向量+相机标定

由于本人部分原创博客发布在古月居论坛&#xff0c;详细内容点击链接跳转&#xff1a; 1. AprilTag探索和原理分析 2. 相机标定&#xff0c;基于AprilTag估算平面法向量

web安全php基础_php常量及可变变量(魔术变量)

常量 php中常量是一个简单值的标识符。该值在脚本中不能改变。 一个常量由英文字母、下划线、和数字组成,但数字不能作为首字母出现。 (常量名不需要加 $ 修饰符)。 常量有两点需要特别注意的地方 常量在整个脚本中都可以使用。常量值被定义后&#xff0c;在脚本的其他任何…

企业级CDP数据工程实践(一):建设中的最佳实践

大家好&#xff0c;许久未见&#xff0c;我是云祁&#xff5e; 今天想和大家分享下 企业级CDP项目 建设中的数据工程实践。 在很多情况下&#xff0c;大家可能会将数据工程与ETL的过程画上等号&#xff0c;但实际上ETL只是数据工程的一部分&#xff0c;其工作量通常仅占整个数据…

I.MX6ULL_Linux_驱动篇(40)异步通知

在前面使用阻塞或者非阻塞的方式来读取驱动中按键值都是应用程序主动读取的&#xff0c;对于非阻塞方式来说还需要应用程序通过 poll 函数不断的轮询。最好的方式就是驱动程序能主动向应用程序发出通知&#xff0c;报告自己可以访问&#xff0c;然后应用程序在从驱动程序中读取…

Linux——进程信号(下)

目录 总结 一&#xff0c;信号保存 1.1 阻塞信号 2.2 信号在内核(操作系统)中的表示 2.3 系统接口 2.3.1 sigset_t信号集 2.3.2 信号集的操作函数 2.3.3 sigprocmask 2.3.4 sigpending 2.4 实验样例 三&#xff0c;信号处理 3.1 信号捕捉 3.2 sigaction接口 3.3 实验…

2022年真题 - 17 - 系统优化

系统优化 题目配置验证配置 题目 StorageSrv - 系统优化 系统资源限制设置&#xff1a;设置所有用户的硬件跟软件的最大进程数、最大文件打开数为65535&#xff1b;开启 IPv4 恶意 icmp 错误消息保护&#xff1b;开启 SYN 洪水攻击保护&#xff1b;允许系统打开的端口范围为 …

服务网关 Gateway

服务网关 Gateway 服务网关介绍Gateway 介绍Gateway 和 Nginx 网关的区别Gateway 核心概念Gateway工作流程 Gateway 案例Predicate&#xff08;断言&#xff09;After 路由谓词工厂Before路由谓词工厂Between 路由谓词工厂Cookie路由谓词工厂Header 路由谓词工厂Host 路由谓词工…

支付宝支付(六):小程序支付(Go+Gin+内网穿透)

一、前置条件 &#xff08;1&#xff09;go语言&#xff0c;1.18 &#xff08;2&#xff09;Gin、第三方依赖包&#xff1a;gopay【github.com/go-pay/gopay/alipay】https://github.com/go-pay/gopay/blob/main/doc/wechat_v3.md &#xff08;3&#xff09;支付宝支付相关信…

Java面向对象程序开发——JDK8新特性

文章目录 网络编程入门知识JDK8新特性Lambda表达式以多线程为例&#xff1a;Lambda结合for循环&#xff1a; Stream流获取一个流的2种常用的方式&#xff1a;常用方法终结方法延迟方法 案例 网络编程入门知识 软件结构、协议分类、网络通信协议、网络编程三要素、TCP通信协议、…

爬虫的分布式思维与实现思路

爬虫的分布式思维与实现思路 基本构架 scrapy-redis实现分布式&#xff0c;其实从原理上来说很简单&#xff0c;这里为描述方便&#xff0c;我们把自己的核心服务器称为master&#xff0c;而把用于跑爬虫程序的机器称为slave 我们知道&#xff0c;采用scrapy框架抓取网页&…

netty学习(4):通过SpringBoot Web发送消息实现netty实现多个客户端与服务器通信

1. 基于netty学习&#xff08;3&#xff09;:SpringBoot整合netty实现多个客户端与服务器通信的学习&#xff0c;要想通过http在netty客户端之间发送消息&#xff0c;需要实现spring-boot-starter-web&#xff0c;封装消息格式&#xff0c;自动调用netty客户端 2. 封装一个简单…

算法笔记——哈希表篇

一般哈希表都是用来快速判断一个元素是否出现集合里&#xff0c;哈希表并不意味着一定要使用HashMap&#xff0c;有时候使用数组更方便&#xff0c;有时候要使用set&#xff0c;依据具体情况而定&#xff0c;哈希表是典型的空间换时间。 数组作为哈希表 一些应用场景就是为数组…