java线程池并发执行,Java线程池实现原理

  java线程池并发执行,Java线程池实现原理

  前沿Java中的线程池在实际项目中有很多场景使用。几乎所有需要索引异步或并发任务的程序都会使用线程池。合理使用线程池可以带来以下好处。

  减少资源消耗:通过重用已创建的线程,减少线程创建和销毁造成的性能消耗。提高响应速度:当任务到达时,它可以立即执行,而无需等待线程的创建。提高线程的可管理性:线程是稀缺资源。如果无限期地创建它们,不仅会消耗系统资源,还会降低系统的稳定性。使用线程池可以统一分配、调优和控制。一、线程池的实现原理

  二、线程池核心对象参数描述公共线程池执行器(int corepool size,

  int maximumPoolSize,

  长keepAliveTime,

  时间单位,

  BlockingQueue可运行工作队列,

  线程工厂线程工厂,

  rejecte execution Handler Handler){线程池的核心对象

  解释

  最小雇佣数量

  池中的核心线程数,corePoolSize是线程池中的最小线程数。即使这些线程处于空闲状态,也不会被销毁,除非设置了allowCoreThreadTimeOut。

  maximumPoolSize

  线程池中的最大线程数,线程池中允许创建的最大线程数。如果队列已满,并且创建的线程数小于最大线程数,线程池将继续创建新线程来执行任务。

  keepAliveTime

  长时间保持线程活动。如果任务很多,每个任务的执行时间很短,可以增加时间,提高线程的利用率。

  工作队列

  任务队列(blocking queue),任务队列有很多种,比如ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue、PriorityBlockingQueue等等。

  线程工厂

  用于创建线程的工厂可以通过线程工厂给每个创建的线程一个更有意义的名字。

  饱和策略

  饱和政策。当队列和线程池满了,就意味着线程池饱和了,那么就必须采用一种策略来处理提交的新任务。默认策略是AbortPolicy,这意味着当无法处理新任务时会引发异常。在JDK 1.5中,线程池框架提供了4种拒绝策略:

  1.AbortPolicy:直接抛出异常。

  2.CallerUnsolicy:只使用调用者所在的线程来运行任务。

  3.DiscardOldestPolicy:丢弃队列中的最佳任务,并执行当前任务。

  4.嫌弃:不治疗,直接扔了。

  Java中常用的三、四种线程池。在Java中使用线程池,可以通过使用ThreadPoolExecutor的构造函数直接创建线程池实例。在Executors类中,我们提供了通用的线程池创建方法。

  接下来,我们来看看常用的四种:

  newFixedThreadPool public static ExecutorService newFixedThreadPool(int nThreads,ThreadFactory threadFactory) {

  返回新的ThreadPoolExecutor(nThreads,nThreads,

  0L,时间单位。毫秒,

  新LinkedBlockingQueue Runnable(),

  threadFactory);

  }从构造方法可以看出,它创建一个固定大小的线程池,每次任务提交时创建一个线程,直到线程达到线程池的最大值nThreads。一旦线程池的大小达到最大,当一个新的任务提交时,它将被放入无界阻塞队列,当一个线程空闲时,该任务将被取出队列继续执行。那么,如何使用newFixedThreadPool呢?让我们举个例子:

  公共类ThreadPoolExecutorsChallenge {

  静态thread factory namedThreadFactory=new ThreadFactoryBuilder()。setNameFormat(demo-pool-%d )。build();

  公共静态void main(String[] args) {

  ExecutorService fixedThreadPool=executors . newfixedthreadpool(3);

  for(int I=0;i i ) {

  final int index=I;

  fixedThreadPool.execute(新的Runnable() {

  @覆盖

  公共无效运行(){

  尝试{

  simple date format SDF=new simple date format( HH:mm:ss );

  System.out.println(运行时间: SDF . format(new Date()) index);

  线程.睡眠(2000年);

  } catch(异常e) {

  e . printstacktrace();

  }

  }

  });

  }

  }

  }运行结果:运行时间:23:56:12 1

  运行时间:23时56分12秒0

  运行时间:23:56:12 2

  运行时间:23时56分14秒3

  运行时间:23:56:14 4上面我创建了一个固定大小为3的线程池,然后在线程池中提交了5个任务。从结果中可以看出,这三个任务一开始都进来了,并被立即执行。提交第四个任务时,第四个任务被放入队列,等待空闲线程(前三个任务的运行时间是一样的。

  这只是为了演示效果。如果正常,手动创建线程池会更好。不允许执行者在生产环境中创建线程池。建议使用ThreadPoolExecutor来创建,这样可以避免资源耗尽的风险。

  描述:

  执行器返回线程池对象的缺点如下:

  FixedThreadPool和SingleThreadPool:允许的请求队列长度是整数。MAX_VALUE,可能会堆积大量对的请求,导致OOM。CacheThreadPool和ScheduledThreadPool:允许的创建线程数是整数。MAX_VALUE,可能会创建大量线程,导致OOM。newCachedThreadPool公共静态执行器服务newCachedThreadPool() {

  返回新的ThreadPoolExecutor(0,整数。MAX_VALUE,

  60L,时间单位。秒,

  新同步队列可运行

  }使用newCachedThreadPool线程池:

  公共类ThreadPoolExecutorsChallenge {

  公共静态void main(String[] args) {

  ExecutorService fixedThreadPool=executors . newcachedthreadpool();

  for(int I=0;i i ) {

  final int index=I;

  fixedThreadPool.execute(新的Runnable() {

  @覆盖

  公共无效运行(){

  尝试{

  simple date format SDF=new simple date format( HH:mm:ss );

  System.out.println(运行时间: SDF . format(new Date()) index);

  线程.睡眠(2000年);

  } catch(异常e) {

  e . printstacktrace();

  }

  }

  });

  }

  }

  }运行结果:运行时间:23:39:04 3

  运行时间:23时39分04秒1

  运行时间:23时39分04秒2

  运行时间:23时39分04秒0

  运行时间:23:39:04 4由于这种线程有新的任务提交,它会创建一个新的线程(线程池中没有空闲线程时),所以不需要等待,所以提交的五个任务的运行时间是一样的。通过Executors.newCachedThreadPool()创建线程池可能会创建大量线程,导致OOM。

  newSingleThreadExecutor public static executor service newSingleThreadExecutor(){

  返回新的FinalizableDelegatedExecutorService

  (新的ThreadPoolExecutor(1,1,

  0L,时间单位。毫秒,

  new LinkedBlockingQueue Runnable()));

  }从构造方法可以看出,它创建的是单线程线程池。它将只使用唯一的工作线程来执行任务,确保所有任务都按指定的顺序执行。那么,如何使用newSingleThreadExecutor呢?让我们举个例子:

  公共类ThreadPoolExecutorsChallenge {

  公共静态void main(String[] args) {

  ExecutorService fixedThreadPool=executors . newsinglethreadexecutor();

  for(int I=0;i i ) {

  final int index=I;

  fixedThreadPool.execute(新的Runnable() {

  @覆盖

  公共无效运行(){

  尝试{

  simple date format SDF=new simple date format( HH:mm:ss );

  System.out.println(运行时间: SDF . format(new Date()) index);

  线程.睡眠(2000年);

  } catch(异常e) {

  e . printstacktrace();

  }

  }

  });

  }

  }

  }因为这个线程池类似于单线程执行,先执行上一个任务,然后每隔2秒顺序执行下一个任务。运行结果如下:

  运行时间:23时47分05秒0

  运行时间:23时47分07秒1

  运行时间:23时47分09秒2

  运行时间:23时47分11秒3

  运行时间:23:47:13 4 newscheduledthreadpool该方法创建一个固定大小的线程池,支持调度和周期性的任务执行。首先,看一下定时执行的例子:

  公共类ThreadPoolExecutorsChallenge {

  公共静态void main(String[] args) {

  final simple date format SDF=new simple date format( HH:mm:ss );

  ScheduledExecutorService scheduledThreadPool=executors . newscheduledthreadpool(3);

  System.out.println(任务提交时间: SDF . format(new Date()));

  scheduledthreadpool . schedule(new Runnable(){

  @覆盖

  公共无效运行(){

  System.out.println(任务运行时间: SDF。format(new Date()));

  }

  },3,时间单位。秒);

  scheduledthreadpool。关闭();

  }

  }使用该线程池的安排方法,延迟3秒钟后执行任务,运行结果如下:

  任务提交时间:23:54:22

  任务运行时间:23:54:25同时使用新计划线程池可以实现周期执行的例子,实现延迟一秒后每个三秒执行一次任务:

  公共类ThreadPoolExecutorsChallenge {

  公共静态void main(String[] args) {

  最终简单日期格式SDF=新的简单日期格式( HH:mm:ss );

  ScheduledExecutorService scheduledThreadPool=executors。newscheduledthreadpool(3);

  System.out.println(提交时间: SDF。format(new Date()));

  scheduledthreadpool。scheduleatfixedrate(new Runnable(){

  @覆盖

  公共无效运行(){

  System.out.println(运行时间: SDF。format(new Date()));

  }

  },1,3,时间单位。秒);

  }

  }运行结果:提交时间: 00:03:15

  运行时间: 00:03:16

  运行时间: 00:03:19

  运行时间: 00:03:22

  运行时间: 00:03:25

  运行时间: 00:03:28四、推荐避免耗尽的风险,推荐创建线程池方式:

  //获取系统处理器个数,作为线程池数量

  int nThreads=Runtime.getRuntime().可用处理器();

  线程工厂名称线程工厂=新线程工厂构建器()。setNameFormat(demo-pool-%d ).build();

  System.out.println(系统处理器个数: n个线程);

  ExecutorService pool=new ThreadPoolExecutor(n个线程,200,0L,时间单位.毫秒,新LinkedBlockingQueue Runnable(1024),namedThreadFactory,new ThreadPoolExecutor .中止策略());

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: