《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

 


  
  1. public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
  2. return new DelegatedScheduledExecutorService
  3. (new ScheduledThreadPoolExecutor(1));
  4. }
  5. static class DelegatedScheduledExecutorService
  6. extends DelegatedExecutorService
  7. implements ScheduledExecutorService {
  8. private final ScheduledExecutorService e;
  9. DelegatedScheduledExecutorService(ScheduledExecutorService executor) {
  10. super(executor);
  11. e = executor;
  12. }

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

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


  
  1. public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
  2. long initialDelay,
  3. long delay,
  4. TimeUnit unit) {
  5. if (command == null || unit == null)
  6. throw new NullPointerException();
  7. if (delay <= 0)
  8. throw new IllegalArgumentException();
  9. ScheduledFutureTask<Void> sft =
  10. new ScheduledFutureTask<Void>(command,
  11. null,
  12. triggerTime(initialDelay, unit),
  13. unit.toNanos(-delay));
  14. RunnableScheduledFuture<Void> t = decorateTask(command, sft);
  15. sft.outerTask = t;
  16. // 延迟执行
  17. delayedExecute(t);
  18. return t;
  19. }
  20. private void delayedExecute(RunnableScheduledFuture<?> task) {
  21. if (isShutdown())
  22. reject(task);
  23. else {
  24. // 加入任务队列
  25. super.getQueue().add(task);
  26. if (isShutdown() &&
  27. !canRunInCurrentRunState(task.isPeriodic()) &&
  28. remove(task))
  29. task.cancel(false);
  30. else
  31. // 确保执行
  32. ensurePrestart();
  33. }
  34. }
  35. // 如果worker数量小于corePoolSize,创建新的线程,其他情况不处理
  36. void ensurePrestart() {
  37. int wc = workerCountOf(ctl.get());
  38. if (wc < corePoolSize)
  39. addWorker(null, true);
  40. else if (wc == 0)
  41. addWorker(null, false);
  42. }

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


  
  1. public ScheduledFuture<?> schedule(Runnable command,
  2. long delay,
  3. TimeUnit unit) {
  4. if (command == null || unit == null)
  5. throw new NullPointerException();
  6. RunnableScheduledFuture<?> t = decorateTask(command,
  7. new ScheduledFutureTask<Void>(command, null,
  8. triggerTime(delay, unit)));
  9. delayedExecute(t);
  10. return t;
  11. }

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


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

 

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


  
  1. private int awaitDone(boolean timed, long nanos)
  2. throws InterruptedException {
  3. final long deadline = timed ? System.nanoTime() + nanos : 0L;
  4. WaitNode q = null;
  5. boolean queued = false;
  6. for (;;) {
  7. if (Thread.interrupted()) {
  8. removeWaiter(q);
  9. throw new InterruptedException();
  10. }
  11. int s = state;
  12. if (s > COMPLETING) {
  13. if (q != null)
  14. q.thread = null;
  15. return s;
  16. }
  17. else if (s == COMPLETING) // cannot time out yet
  18. Thread.yield();
  19. else if (q == null)
  20. q = new WaitNode();
  21. else if (!queued)
  22. queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
  23. q.next = waiters, q);
  24. else if (timed) {
  25. nanos = deadline - System.nanoTime();
  26. if (nanos <= 0L) {
  27. removeWaiter(q);
  28. return state;
  29. }
  30. //注意这里
  31. LockSupport.parkNanos(this, nanos);
  32. }
  33. else //注意这里
  34. LockSupport.park(this);
  35. }
  36. }

 

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

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

4、使用


  
  1. ScheduledExecutorService single = Executors.newSingleThreadScheduledExecutor();
  2. Runnable runnable1 = () -> {
  3. try {
  4. Thread.sleep(4000);
  5. System.out.println("11111111111111");
  6. } catch (InterruptedException e) {
  7. e.printStackTrace();
  8. }
  9. };
  10. Runnable runnable2 = () -> {
  11. try {
  12. Thread.sleep(4000);
  13. System.out.println("222");
  14. } catch (InterruptedException e) {
  15. e.printStackTrace();
  16. }
  17. };
  18. single.scheduleWithFixedDelay(runnable1,0,1, TimeUnit.SECONDS);
  19. single.scheduleWithFixedDelay(runnable2,0,2, TimeUnit.SECONDS);

  
  1. 11111111111111
  2. 222
  3. 11111111111111
  4. 222
  5. 11111111111111

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


  
  1. actionService = Executors.newSingleThreadScheduledExecutor();
  2. actionService.scheduleWithFixedDelay(() -> {
  3. try {
  4. Thread.currentThread().setName("robotActionService");
  5. Integer robotId = robotQueue.poll();
  6. if (robotId == null) {
  7. // 关闭线程池
  8. actionService.shutdown();
  9. } else {
  10. int aiLv = robots.get(robotId);
  11. if (actionQueueMap.containsKey(aiLv)) {
  12. ActionQueue actionQueue = actionQueueMap.get(aiLv);
  13. actionQueue.doAction(robotId);
  14. }
  15. }
  16. } catch (Exception e) {
  17. // 捕捉异常
  18. LOG.error("",e);
  19. }
  20. }, 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个月内不可修改。