《Java并发库系列三》一newSingleThreadScheduledExecutor

举报
香菜聊游戏 发表于 2021/07/15 02:02:01 2021/07/15
【摘要】   newSingleThreadScheduledExecutor:产生一个ScheduledExecutorService对象,这个对象的线程池大小为1,如果任务多于一个,任务将按先后顺序执行。 1、继承结构 构造函数 包含一个定时的service   public static ScheduledExecutorService newSi...

 

newSingleThreadScheduledExecutor:产生一个ScheduledExecutorService对象,这个对象的线程池大小为1,如果任务多于一个,任务将按先后顺序执行。

1、继承结构

构造函数

包含一个定时的service

 


      public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
      return new DelegatedScheduledExecutorService
       (new ScheduledThreadPoolExecutor(1));
      }
      static class DelegatedScheduledExecutorService
      extends DelegatedExecutorService
      implements ScheduledExecutorService {
      private final ScheduledExecutorService e;
       DelegatedScheduledExecutorService(ScheduledExecutorService executor) {
      super(executor);
       e = executor;
       }
  
 

2、怎么保证只有一个线程

定时执行的时候调用这个方法,调用过程如下,注意看其中的注释,由上往下的调用顺序


      public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
      long initialDelay,
      long delay,
       TimeUnit unit) {
      if (command == null || unit == null)
      throw new NullPointerException();
      if (delay <= 0)
      throw new IllegalArgumentException();
       ScheduledFutureTask<Void> sft =
      new ScheduledFutureTask<Void>(command,
      null,
       triggerTime(initialDelay, unit),
       unit.toNanos(-delay));
       RunnableScheduledFuture<Void> t = decorateTask(command, sft);
       sft.outerTask = t;
      // 延迟执行
       delayedExecute(t);
      return t;
      }
      private void delayedExecute(RunnableScheduledFuture<?> task) {
      if (isShutdown())
       reject(task);
      else {
      // 加入任务队列
      super.getQueue().add(task);
      if (isShutdown() &&
       !canRunInCurrentRunState(task.isPeriodic()) &&
       remove(task))
       task.cancel(false);
      else
      // 确保执行
       ensurePrestart();
       }
      }
      // 如果worker数量小于corePoolSize,创建新的线程,其他情况不处理
      void ensurePrestart() {
      int wc = workerCountOf(ctl.get());
      if (wc < corePoolSize)
       addWorker(null, true);
      else if (wc == 0)
       addWorker(null, false);
      }
  
 

3、怎么保证时间可以定时执行


      public ScheduledFuture<?> schedule(Runnable command,
      long delay,
       TimeUnit unit) {
      if (command == null || unit == null)
      throw new NullPointerException();
       RunnableScheduledFuture<?> t = decorateTask(command,
      new ScheduledFutureTask<Void>(command, null,
       triggerTime(delay, unit)));
       delayedExecute(t);
      return t;
      }
  
 

 在每次执行的时候会把下一次执行的时间放进任务中


      private long triggerTime(long delay, TimeUnit unit) {
      return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));
      }
      /**
       * Returns the trigger time of a delayed action.
       */
      long triggerTime(long delay) {
      return now() +
       ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
      }
  
 

 

 FutureTask 定时是通过LockSupport.parkNanos(this, nanos);LockSupport.park(this);


      private int awaitDone(boolean timed, long nanos)
      throws InterruptedException {
      final long deadline = timed ? System.nanoTime() + nanos : 0L;
       WaitNode q = null;
      boolean queued = false;
      for (;;) {
      if (Thread.interrupted()) {
       removeWaiter(q);
      throw new InterruptedException();
       }
      int s = state;
      if (s > COMPLETING) {
      if (q != null)
       q.thread = null;
      return s;
       }
      else if (s == COMPLETING) // cannot time out yet
       Thread.yield();
      else if (q == null)
       q = new WaitNode();
      else if (!queued)
       queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
       q.next = waiters, q);
      else if (timed) {
       nanos = deadline - System.nanoTime();
      if (nanos <= 0L) {
       removeWaiter(q);
      return state;
       }
      //注意这里
       LockSupport.parkNanos(this, nanos);
       }
      else //注意这里
       LockSupport.park(this);
       }
      }
  
 

 

总结:Executor是通过将任务放在队列中,生成的futureTask。然后将生成的任务在队列中排序,将时间最近的需要出发的任务做检查。如果时间不到,就阻塞线程到下次出发时间。

注意:newSingleThreadScheduledExecutor只会有一个线程,不管你提交多少任务,这些任务会顺序执行,如果发生异常会取消下面的任务,线程池也不会关闭,注意捕捉异常

4、使用


      ScheduledExecutorService single = Executors.newSingleThreadScheduledExecutor();
      Runnable runnable1 = () -> {
      try {
       Thread.sleep(4000);
       System.out.println("11111111111111");
       } catch (InterruptedException e) {
       e.printStackTrace();
       }
      };
      Runnable runnable2 = () -> {
      try {
       Thread.sleep(4000);
       System.out.println("222");
       } catch (InterruptedException e) {
       e.printStackTrace();
       }
      };
      single.scheduleWithFixedDelay(runnable1,0,1, TimeUnit.SECONDS);
      single.scheduleWithFixedDelay(runnable2,0,2, TimeUnit.SECONDS);
  
 

      11111111111111
      222
      11111111111111
      222
      11111111111111
  
 

 在项目中要注意关闭线程池


      actionService = Executors.newSingleThreadScheduledExecutor();
       actionService.scheduleWithFixedDelay(() -> {
      try {
       Thread.currentThread().setName("robotActionService");
       Integer robotId = robotQueue.poll();
      if (robotId == null) {
      // 关闭线程池
       actionService.shutdown();
       } else {
      int aiLv = robots.get(robotId);
      if (actionQueueMap.containsKey(aiLv)) {
       ActionQueue actionQueue = actionQueueMap.get(aiLv);
       actionQueue.doAction(robotId);
       }
       }
       } catch (Exception e) {
      // 捕捉异常
       LOG.error("",e);
       }
       }, 1, 1, TimeUnit.SECONDS);
  
 

欢迎转载,我是香菜,谢谢。欢迎加入QQ群:632603498,一起学习

 

 

 

 

文章来源: gamwatcher.blog.csdn.net,作者:香菜聊游戏,版权归原作者所有,如需转载,请联系作者。

原文链接:gamwatcher.blog.csdn.net/article/details/88536377

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。