广告
返回顶部
首页 > 资讯 > 精选 >Java线程池是怎么工作的
  • 474
分享到

Java线程池是怎么工作的

2023-06-27 11:06:44 474人浏览 独家记忆
摘要

本篇内容介绍了“Java线程池是怎么工作的”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!线程池的工作原理首先我们看下当一个新的任务提交到线程

本篇内容介绍了“Java线程池是怎么工作的”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

线程池的工作原理

首先我们看下当一个新的任务提交到线程池之后,线程池是如何处理的

线程池判断核心线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作线程来执行任务。如果核心线程池里的线程都在执行任务,则执行第二步。

线程池判断工作队列是否已经满。如果工作队列没有满,则将新提交的任务存储在这个工作队列里进行等待。如果工作队列满了,则执行第三步

线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务

线程池饱和策略

这里提到了线程池的饱和策略,那我们就简单介绍下有哪些饱和策略:

AbortPolicy

为Java线程池默认的阻塞策略,不执行此任务,而且直接抛出一个运行时异常,切记ThreadPoolExecutor.execute需要try catch,否则程序会直接退出。

DiscardPolicy

直接抛弃,任务不执行,空方法

DiscardOldestPolicy

从队列里面抛弃head的一个任务,并再次execute 此task。

CallerRunsPolicy

在调用execute的线程里面执行此command,会阻塞入口

用户自定义拒绝策略(最常用)

实现RejectedExecutionHandler,并自己定义策略模式

下我们以ThreadPoolExecutor为例展示下线程池的工作流程图

Java线程池是怎么工作的
Java线程池是怎么工作的

如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(注意,执行这一步骤需要获取全局)。

如果运行的线程等于或多于corePoolSize,则将任务加入BlockingQueue。

如果无法将任务加入BlockingQueue(队列已满),则在非corePool中创建新的线程来处理任务(注意,执行这一步骤需要获取全局锁)。

如果创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并调用RejectedExecutionHandler.rejectedExecution()方法。

ThreadPoolExecutor采取上述步骤的总体设计思路,是为了在执行execute()方法时,尽可能地避免获取全局锁(那将会是一个严重的可伸缩瓶颈)。在ThreadPoolExecutor完成预热之后(当前运行的线程数大于等于corePoolSize),几乎所有的execute()方法调用都是执行步骤2,而步骤2不需要获取全局锁。

关键方法源码分析

我们看看核心方法添加到线程池方法execute的源码如下:

    //    //Executes the given task sometime in the future.  The task    //may execute in a new thread or in an existing pooled thread.    //    // If the task cannot be submitted for execution, either because this    // executor has been shutdown or because its capacity has been reached,    // the task is handled by the current {@code RejectedExecutionHandler}.    //    // @param command the task to execute    // @throws RejectedExecutionException at discretion of    //         {@code RejectedExecutionHandler}, if the task    //         cannot be accepted for execution    // @throws NullPointerException if {@code command} is null    //   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.        // 翻译如下:        // 判断当前的线程数是否小于corePoolSize如果是,使用入参任务通过addWord方法创建一个新的线程,        // 如果能完成新线程创建exexute方法结束,成功提交任务        // 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.        // 翻译如下:        // 在第一步没有完成任务提交;状态为运行并且能否成功加入任务到工作队列后,再进行一次check,如果状态        // 在任务加入队列后变为了非运行(有可能是在执行到这里线程池shutdown了),非运行状态下当然是需要        // reject;然后再判断当前线程数是否为0(有可能这个时候线程数变为了0),如是,新增一个线程;        // 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.        // 翻译如下:        // 如果不能加入任务到工作队列,将尝试使用任务新增一个线程,如果失败,则是线程池已经shutdown或者线程池        // 已经达到饱和状态,所以reject这个他任务        //       int c = ctl.get();       // 工作线程数小于核心线程数       if (workerCountOf(c)

下面我们继续看看addWorker是如何实现的:

 private boolean addWorker(Runnable firstTask, boolean core) {       // java标签       retry:       // 死循环       for (;;) {           int c = ctl.get();           // 获取当前线程状态           int rs = runStateOf(c);           // Check if queue empty only if necessary.           // 这个逻辑判断有点绕可以改成           // rs >= shutdown && (rs != shutdown || firstTask != null || workQueue.isEmpty())           // 逻辑判断成立可以分为以下几种情况均不接受新任务           // 1、rs > shutdown:--不接受新任务           // 2、rs >= shutdown && firstTask != null:--不接受新任务           // 3、rs >= shutdown && workQueue.isEmppty:--不接受新任务           // 逻辑判断不成立           // 1、rs==shutdown&&firstTask != null:此时不接受新任务,但是仍会执行队列中的任务           // 2、rs==shotdown&&firstTask == null:会执行addWork(null,false)           //  防止了SHUTDOWN状态下没有活动线程了,但是队列里还有任务没执行这种特殊情况。           //  添加一个null任务是因为SHUTDOWN状态下,线程池不再接受新任务           if (rs >= SHUTDOWN &&! (rs == SHUTDOWN && firstTask == null &&! workQueue.isEmpty()))               return false;           // 死循环           // 如果线程池状态为RUNNING并且队列中还有需要执行的任务           for (;;) {               // 获取线程池中线程数量               int wc = workerCountOf(c);               // 如果超出容量或者最大线程池容量不在接受新任务               if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize))                   return false;               // 线程安全增加工作线程数               if (compareAndIncrementWorkerCount(c))                   // 跳出retry                   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 {           final ReentrantLock mainLock = this.mainLock;           w = new Worker(firstTask);           final Thread t = w.thread;           if (t != null) {               // 加锁               mainLock.lock();               try {                   // Recheck while holding lock.                   // Back out on ThreadFactory failure or if                   // shut down before lock acquired.                   int c = ctl.get();                   int rs = runStateOf(c);                   // RUNNING状态 || SHUTDONW状态下清理队列中剩余的任务                   if (rs if (t.isAlive()) // precheck that t is startable                           throw new IllegalThreadStateException();                       // 将新启动的线程添加到线程池中                       workers.add(w);                       // 更新线程池线程数且不超过最大值                       int s = workers.size();                       if (s > largestPoolSize)                           largestPoolSize = s;                       workerAdded = true;                   }               } finally {                   mainLock.unlock();               }               // 启动新添加的线程,这个线程首先执行firstTask,然后不停的从队列中取任务执行               if (workerAdded) {                   //执行ThreadPoolExecutor的runWoker方法                   t.start();                   workerStarted = true;               }           }       } finally {           // 线程启动失败,则从wokers中移除w并递减wokerCount           if (! workerStarted)               // 递减wokerCount会触发tryTerminate方法               addWorkerFailed(w);       }       return workerStarted;   }

addWorker之后是runWorker,第一次启动会执行初始化传进来的任务firstTask;然后会从workQueue中取任务执行,如果队列为空则等待keepAliveTime这么长时间

final void runWorker(Worker w) {       Thread wt = Thread.currentThread();       Runnable task = w.firstTask;       w.firstTask = null;       // 允许中断       w.unlock(); // allow interrupts       boolean completedAbruptly = true;       try {           // 如果getTask返回null那么getTask中会将workerCount递减,如果异常了这个递减操作会在processWorkerExit中处理           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               if ((runStateAtLeast(ctl.get(), STOP) ||                    (Thread.interrupted() &&                     runStateAtLeast(ctl.get(), STOP))) &&                   !wt.isInterrupted())                   wt.interrupt();               try {                   beforeExecute(wt, task);                   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);                   }               } finally {                   task = null;                   w.completedTasks++;                   w.unlock();               }           }           completedAbruptly = false;       } finally {           processWorkerExit(w, completedAbruptly);       }   }

我们看下getTask是如何执行的

private Runnable getTask() {       boolean timedOut = false; // Did the last poll() time out?       // 死循环       retry: for (;;) {           // 获取线程池状态           int c = ctl.get();           int rs = runStateOf(c);           // Check if queue empty only if necessary.           // 1.rs > SHUTDOWN 所以rs至少等于STOP,这时不再处理队列中的任务           // 2.rs = SHUTDOWN 所以rs>=STOP肯定不成立,这时还需要处理队列中的任务除非队列为空           // 这两种情况都会返回null让runWoker退出while循环也就是当前线程结束了,所以必须要decrement           if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {               // 递减workerCount值               decrementWorkerCount();               return null;           }           // 标记从队列中取任务时是否设置超时时间           boolean timed; // Are workers subject to culling?           // 1.RUNING状态           // 2.SHUTDOWN状态,但队列中还有任务需要执行           for (;;) {               int wc = workerCountOf(c);               // 1.core thread允许被超时,那么超过corePoolSize的的线程必定有超时               // 2.allowCoreThreadTimeOut == false && wc >               // corePoolSize时,一般都是这种情况,core thread即使空闲也不会被回收,只要超过的线程才会               timed = allowCoreThreadTimeOut || wc > corePoolSize;               // 从addWorker可以看到一般wc不会大于maximumPoolSize,所以更关心后面半句的情形:               // 1. timedOut == false 第一次执行循环, 从队列中取出任务不为null方法返回 或者               // poll出异常了重试               // 2.timeOut == true && timed ==               // false:看后面的代码workerQueue.poll超时时timeOut才为true,               // 并且timed要为false,这两个条件相悖不可能同时成立(既然有超时那么timed肯定为true)               // 所以超时不会继续执行而是return null结束线程。               if (wc break;               // workerCount递减,结束当前thread               if (compareAndDecrementWorkerCount(c))                   return null;               c = ctl.get(); // Re-read ctl               // 需要重新检查线程池状态,因为上述操作过程中线程池可能被SHUTDOWN               if (runStateOf(c) != rs)                   continue retry;               // else CAS failed due to workerCount change; retry inner loop           }           try {               // 1.以指定的超时时间从队列中取任务               // 2.core thread没有超时               Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take();               if (r != null)                   return r;               timedOut = true;// 超时           } catch (InterruptedException retry) {               timedOut = false;// 线程被中断重试           }       }   }

下面我们看下processWorkerExit是如何工作的

private void processWorkerExit(Worker w, boolean completedAbruptly) {       // 正常的话再runWorker的getTask方法workerCount已经被减一了       if (completedAbruptly)           decrementWorkerCount();       final ReentrantLock mainLock = this.mainLock;       mainLock.lock();       try {           // 累加线程的completedTasks           completedTaskCount += w.completedTasks;           // 从线程池中移除超时或者出现异常的线程           workers.remove(w);       } finally {           mainLock.unlock();       }       // 尝试停止线程池       tryTerminate();       int c = ctl.get();       // runState为RUNNING或SHUTDOWN       if (runStateLessThan(c, STOP)) {           // 线程不是异常结束           if (!completedAbruptly) {               // 线程池最小空闲数,允许core thread超时就是0,否则就是corePoolSize               int min = allowCoreThreadTimeOut ? 0 : corePoolSize;               // 如果min == 0但是队列不为空要保证有1个线程来执行队列中的任务               if (min == 0 && !workQueue.isEmpty())                   min = 1;               // 线程池还不为空那就不用担心了               if (workerCountOf(c) >= min)                   return; // replacement not needed           }           // 1.线程异常退出           // 2.线程池为空,但是队列中还有任务没执行,看addWoker方法对这种情况的处理           addWorker(null, false);       }   }

tryTerminate

processWorkerExit方法中会尝试调用tryTerminate来终止线程池。这个方法在任何可能导致线程池终止的动作后执行:比如减少wokerCount或SHUTDOWN状态下从队列中移除任务。

final void tryTerminate() {       for (;;) {           int c = ctl.get();           // 以下状态直接返回:           // 1.线程池还处于RUNNING状态           // 2.SHUTDOWN状态但是任务队列非空           // 3.runState >= TIDYING 线程池已经停止了或在停止了           if (isRunning(c) || runStateAtLeast(c, TIDYING) || (runStateOf(c) == SHUTDOWN && !workQueue.isEmpty()))               return;           // 只能是以下情形会继续下面的逻辑:结束线程池。           // 1.SHUTDOWN状态,这时不再接受新任务而且任务队列也空了           // 2.STOP状态,当调用了shutdownNow方法           // workerCount不为0则还不能停止线程池,而且这时线程都处于空闲等待的状态           // 需要中断让线程“醒”过来,醒过来的线程才能继续处理shutdown的信号。           if (workerCountOf(c) != 0) { // Eligible to terminate               // runWoker方法中w.unlock就是为了可以被中断,getTask方法也处理了中断。               // ONLY_ONE:这里只需要中断1个线程去处理shutdown信号就可以了。               interruptIdleWorkers(ONLY_ONE);               return;           }           final ReentrantLock mainLock = this.mainLock;           mainLock.lock();           try {               // 进入TIDYING状态               if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {                   try {                       // 子类重载:一些资源清理工作                       terminated();                   } finally {                       // TERMINATED状态                       ctl.set(ctlOf(TERMINATED, 0));                       // 继续awaitTermination                       termination.signalAll();                   }                   return;               }           } finally {               mainLock.unlock();           }           // else retry on failed CAS       }   }

shutdown这个方法会将runState置为SHUTDOWN,会终止所有空闲的线程。shutdownNow方法将runState置为STOP。和shutdown方法的区别,这个方法会终止所有的线程。主要区别在于shutdown调用的是interruptIdleWorkers这个方法,而shutdownNow实际调用的是Worker类的interruptIfStarted方法:

他们的实现如下:

public void shutdown() {       final ReentrantLock mainLock = this.mainLock;       mainLock.lock();       try {           checkShutdownAccess();           // 线程池状态设为SHUTDOWN,如果已经至少是这个状态那么则直接返回           advanceRunState(SHUTDOWN);           // 注意这里是中断所有空闲的线程:runWorker中等待的线程被中断 → 进入processWorkerExit →           // tryTerminate方法中会保证队列中剩余的任务得到执行。           interruptIdleWorkers();           onShutdown(); // hook for ScheduledThreadPoolExecutor       } finally {           mainLock.unlock();       }       tryTerminate();   }public List shutdownNow() {   List tasks;   final ReentrantLock mainLock = this.mainLock;   mainLock.lock();   try {       checkShutdownAccess();       // STOP状态:不再接受新任务且不再执行队列中的任务。       advanceRunState(STOP);       // 中断所有线程       interruptWorkers();       // 返回队列中还没有被执行的任务。       tasks = drainQueue();   }   finally {       mainLock.unlock();   }   tryTerminate();   return tasks;}private void interruptIdleWorkers(boolean onlyOne) {   final ReentrantLock mainLock = this.mainLock;   mainLock.lock();   try {       for (Worker w : workers) {           Thread t = w.thread;           // w.tryLock能获取到锁,说明该线程没有在运行,因为runWorker中执行任务会先lock,           // 因此保证了中断的肯定是空闲的线程。           if (!t.isInterrupted() && w.tryLock()) {               try {                   t.interrupt();               } catch (SecurityException ignore) {               } finally {                   w.unlock();               }           }           if (onlyOne)               break;       }   }   finally {       mainLock.unlock();   }}void interruptIfStarted() {   Thread t;   // 初始化时state == -1   if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {       try {           t.interrupt();       } catch (SecurityException ignore) {       }   }}

线程池的使用

线程池的创建

我们可以通过ThreadPoolExecutor来创建一个线程池

      public ThreadPoolExecutor(int corePoolSize,              int maximumPoolSize,              long keepAliveTime,              TimeUnit unit,              BlockingQueue workQueue) {       // threadFactory用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字       this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,               Executors.defaultThreadFactory(), defaultHandler);   }
向线程池提交任务

可以使用两个方法向线程池提交任务,分别为execute()和submit()方法。execute()方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功。通过以下代码可知execute()方法输入的任务是一个Runnable类的实例。

threadsPool.execute(new Runnable() {       @Override       public void run() {       }   });

submit()方法用于提交需要返回值的任务。线程池会返回一个future类型的对象,通过这个future对象可以判断任务是否执行成功,并且可以通过future的get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。

Future future = executor.submit(harReturnValuetask); try   {       Object s = future.get();   }catch(   InterruptedException e)   {       // 处理中断异常   }catch(   ExecutionException e)   {       // 处理无法执行任务异常   }finally   {       // 关闭线程池       executor.shutdown();   }
关闭线程池

可以通过调用线程池的shutdown或shutdownNow方法来关闭线程池。它们的原理是遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止。但是它们存在一定的区别,shutdownNow首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表,而shutdown只是将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。

只要调用了这两个关闭方法中的任意一个,isshutdown方法就会返回true。当所有的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。至于应该调用哪一种方法来关闭线程池,应该由提交到线程池的任务特性决定,通常调用shutdown方法来关闭线程池,如果任务不一定要执行完,则可以调用shutdownNow方法。

合理的配置线程池

要想合理地配置线程池,就必须首先分析任务特性,可以从以下几个角度来分析。

任务的性质:CPU密集型任务、IO密集型任务和混合型任务。

任务的优先级:高、中和低。

任务的执行时间:长、中和短。

任务的依赖性:是否依赖其他系统资源,如数据库连接。

性质不同的任务可以用不同规模的线程池分开处理。CPU密集型任务应配置尽可能小的线程,如配置Ncpu+1个线程的线程池。由于IO密集型任务线程并不是一直在执行任务,则应配置尽可能多的线程,如2*Ncpu。混合型的任务,如果可以拆分,将其拆分成一个CPU密集型任务和一个IO密集型任务,只要这两个任务执行的时间相差不是太大,那么分解后执行的吞吐量将高于串行执行的吞吐量。如果这两个任务执行时间相差太大,则没必要进行分解。可以通过Runtime.getRuntime().availableProcessors()方法获得当前设备的CPU个数。优先级不同的任务可以使用优先级队列PriorityBlockingQueue来处理。它可以让优先级高的任务先执行

如果一直有优先级高的任务提交到队列里,那么优先级低的任务可能永远不能执行。执行时间不同的任务可以交给不同规模的线程池来处理,或者可以使用优先级队列,让执行时间短的任务先执行。依赖数据库连接池的任务,因为线程提交sql后需要等待数据库返回结果,等待的时间越长,则CPU空闲时间就越长,那么线程数应该设置得越大,这样才能更好地利用CPU。

建议使用有界队列。有界队列能增加系统的稳定性和预警能力,可以根据需要设大一点儿,比如几千。有时候我们系统里后台任务线程池的队列和线程池全满了,不断抛出抛弃任务的异常,通过排查发现是数据库出现了问题,导致执行SQL变得非常缓慢,因为后台任务线程池里的任务全是需要向数据库查询和插入数据的,所以导致线程池里的工作线程全部阻塞,任务积压在线程池里。如果当时我们设置成无界队列,那么线程池的队列就会越来越多,有可能会撑满内存,导致整个系统不可用,而不只是后台任务出现问题。当然,我们的系统所有的任务是用单独的服务器部署的,我们使用不同规模的线程池完成不同类型的任务,但是出现这样问题时也会影响到其他任务。

线程池的监控

如果在系统中大量使用线程池,则有必要对线程池进行监控,方便在出现问题时,可以根据线程池的使用状况快速定位问题。可以通过线程池提供的参数进行监控,在监控线程池的时候可以使用以下属性

  • taskCount:线程池需要执行的任务数量。
  • completedTaskCount:线程池在运行过程中已完成的任务数量,小于或等于taskCount。
  • largestPoolSize:线程池里曾经创建过的最大线程数量。通过这个数据可以知道线程池是否曾经满过。如该数值等于线程池的最大大小,则表示线程池曾经满过。
  • getPoolSize:线程池的线程数量。如果线程池不销毁的话,线程池里的线程不会自动销毁,所以这个大小只增不减。
  • getActiveCount:获取活动的线程数。

通过扩展线程池进行监控。可以通过继承线程池来自定义线程池,重写线程池的beforeExecute、afterExecute和terminated方法,也可以在任务执行前、执行后和线程池关闭前执行一些代码来进行监控。例如,监控任务的平均执行时间、最大执行时间和最小执行时间等。

“Java线程池是怎么工作的”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: Java线程池是怎么工作的

本文链接: https://www.lsjlt.com/news/310223.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java线程池是怎么工作的
    本篇内容介绍了“Java线程池是怎么工作的”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!线程池的工作原理首先我们看下当一个新的任务提交到线程...
    99+
    2023-06-27
  • java线程池的工作原理
    这篇文章主要讲解了“java线程池的工作原理”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“java线程池的工作原理”吧!一、线程池创建先看一下ThreadPoolExecutor参数最全的构...
    99+
    2023-05-30
  • 线程池的工作流程是什么
    本篇内容主要讲解“线程池的工作流程是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“线程池的工作流程是什么”吧!线程池的各种参数面试的时候最常问的就是线程池的...
    99+
    2022-10-19
  • 线程池的工作原理是什么
    这篇文章主要讲解了“线程池的工作原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“线程池的工作原理是什么”吧!线程池的自我介绍我是一个线程池(Thre...
    99+
    2022-10-19
  • Java线程池工作原理和使用方法是什么
    这篇文章主要介绍“Java线程池工作原理和使用方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java线程池工作原理和使用方法是什么”文章能帮助大家解决问题。1. 为什么要使用线程池使用线程...
    99+
    2023-07-04
  • 怎么在Java中使用线程工厂监控线程池
    这期内容当中小编将会给大家带来有关怎么在Java中使用线程工厂监控线程池,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。ThreadFactory线程池中的线程从哪里来呢?就是ThreadFoctorypu...
    99+
    2023-06-14
  • java线程池是什么
    java的线程池是什么,有哪些类型,作用分别是什么 (推荐学习:java课程)线程池是一种多线程处理形式,处理过程中将任务添加队列,然后在创建线程后自动启动这些任务,每个线程都使用默认的堆栈大小,以默认的优先级运行,并处...
    99+
    2016-06-22
    java教程 java
  • 什么是java线程池
    使用线程池的好处有很多,比如节省系统资源的开销,节省创建和销毁线程的时间等,当我们需要处理的任务较多时,就可以使用线程池,可能还有很多用户不知道Java线程池如何使用?今天给大家分享Java四种线程池的使用方法。线程池介绍:线程池是一种多线...
    99+
    2017-06-28
    java入门 java 线程池
  • SpringBoot线程池和Java线程池怎么使用
    这篇文章主要介绍“SpringBoot线程池和Java线程池怎么使用”,在日常操作中,相信很多人在SpringBoot线程池和Java线程池怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”SpringB...
    99+
    2023-07-06
  • 详解Java线程池的使用及工作原理
    目录一、什么是线程池?二、线程池要解决什么问题?三、线程池的使用四、常用阻塞队列五、线程工厂六、拒绝策略七、线程池的执行逻辑八、execute()方法九、执行流程一、什么是线程池? ...
    99+
    2022-11-12
  • Java线程池怎么用
    小编给大家分享一下Java线程池怎么用,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、什么是线程池?线程池是一种用于实现计算机程序并发执行的软件设计模式。线程池...
    99+
    2023-06-15
  • java怎么停止线程池中的线程
    要停止线程池中的线程,可以使用 `ExecutorService` 接口提供的 `shutdown()` 方法来停止线程池。这个方法...
    99+
    2023-08-20
    java
  • java中什么是线程池
    本篇文章为大家展示了java中什么是线程池,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Java可以用来干什么Java主要应用于:1. web开发;2. Android开发;3. 客户端开发;4. ...
    99+
    2023-06-14
  • Java线程池的本质以及作用是什么
    Java线程池的本质以及作用是什么,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。熟悉java多线程的 朋友一定十分了解java的线程池,jdk中的核心实现类为j...
    99+
    2023-06-17
  • java怎么从线程池获取线程
    在 Java 中,可以使用 `ExecutorService` 接口来管理线程池,并从线程池中获取线程。下面是通过线程池获取线程的一...
    99+
    2023-10-11
    java
  • JAVA怎么控制线程池的线程数量
    Java中可以通过使用`ThreadPoolExecutor`类来控制线程池的线程数量。`ThreadPoolExecutor`提供...
    99+
    2023-10-11
    JAVA
  • java连接池的工作原理是什么
    连接池是一种管理数据库连接的技术,它在应用程序初始化时创建一定数量的数据库连接并保存在连接池中,应用程序需要数据库连接时,直接从连接...
    99+
    2023-09-13
    java
  • Java线程池中多余的线程怎么回收
    这篇文章给大家分享的是有关Java线程池中多余的线程怎么回收的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。那么,就以JDK1.8为例分析吧。1.runWorker(Worker w)工作线程启动后,就进入runW...
    99+
    2023-06-15
  • 如何理解线程池的工作原理
    本篇内容主要讲解“如何理解线程池的工作原理”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解线程池的工作原理”吧!什么是线程池「小田螺」 勤勤恳恳,任劳任怨...
    99+
    2022-10-19
  • Java线程池ThreadPoolExecutor怎么创建
    本篇内容介绍了“Java线程池ThreadPoolExecutor怎么创建”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!简介ThreadPo...
    99+
    2023-07-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作