范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

FutureTask简单用法,为何单个任务仅执行一次?

  前几天会员领取情况查询的接口SQL查询超时出故障了,因为有个用户买的会员有点多(哈哈),其实是 数据量大 + 祖传代码逻辑冗长
  尝试的解决方案:  SQL:检查了一下,单个SQL的耗时其实不算大,也能接受,不需要改动,主要原因是后端逻辑冗长  FutureTask获取线程的执行结果:将1次大查询划分为多次小查询同时进行,提高接口响应速度。且一个FutureTask仅执行一次,不会出现重复的查询
  经过权衡,我们选择了后者  一、FutureTask用法
  解决方案要用到线程池搭配FutureTask,这里我们就不用了,简化点  public class Test {    //计算结果     int count=0;  @Test  public void test(){   try{               FutureTask futureTask=new FutureTask<>(new Callable() {              @Override              public Integer call() throws Exception {               return 1;              }             });             //把FutureTask放入线程中,线程会运行FutureTask的run()代码块             Thread t1=new Thread(futureTask);             t1.start();             //获取计算的结果,是一个阻塞等待返回的方法             count+=futureTask.get();         } catch (InterruptedException e) {             e.printStackTrace();         } catch (ExecutionException e) {             e.printStackTrace();         }         //最后结果: 1         System.out.println(count);   } }
  这里用了构造方法 public FutureTask(Callable callable)  让FutureTask持有Callable接口的实例
  用到try-catch是由于 futureTask.get()  方法是一个阻塞等待的过程,途中如果被中断会抛中断异常,别的异常都会以ExecutionException执行异常的形式抛出 二、(重要)FutureTask的任务仅执行一次,为何?
  FutureTask的 run()  代码块仅执行一次!请看注释 /**  执行结果(全局变量), 有2种情况:  1. 顺利完成返回的结果  2. 执行run()代码块过程中抛出的异常 */ private Object outcome;   //正在执行run()的线程, 内存可被其他线程可见 private volatile Thread runner;  public void run() {  /**   FutureTask的run()仅执行一次的原因:   1. state != NEW表示任务正在被执行或已经完成, 直接return   2. 若state==NEW, 则尝试CAS将当前线程 设置为执行run()的线程,如果失败,说明已经有其他线程 先行一步执行了run(),则当前线程return退出  */  if (state != NEW ||!UNSAFE.compareAndSwapObject(this, runnerOffset,null, Thread.currentThread()))   return;  try {   //持有Callable的实例,后续会执行该实例的call()方法   Callable c = callable;   if (c != null && state == NEW) {    V result;    boolean ran;    try {     result = c.call();     ran = true;    }catch (Throwable ex) {     result = null;     ran = false;     //执行中抛的异常会放入outcome中保存     setException(ex);    }    if (ran)     //若无异常, 顺利完成的执行结果会放入outcome保存     set(result);   }  }finally {   // help GC    runner = null;   int s = state;   if (s >= INTERRUPTING)    handlePossibleCancellationInterrupt(s);  } }
  执行 run()  的代码块之后,其他线程如何拿到FutureTask的执行结果?下面的get()  方法可以做到 三、get()获取结果public V get() throws InterruptedException, ExecutionException {      int s = state;     //COMPLETING: 正在完成的状态;  s <= COMPLETING就是未完成     if (s <= COMPLETING)      //不计时等待,结束等待的条件只有【完成】、【被中断】、【被取消】、【抛其他异常(不包括中断异常、取消异常)】         s = awaitDone(false, 0L);     return report(s);  }
  这里提一下线程执行的状态 :  private volatile int state; //线程创建状态 private static final int NEW = 0; //完成(**一个瞬时的标记**)    private static final int COMPLETING = 1; //正常完成状态 private static final int NORMAL = 2; //执行过程出现异常 private static final int EXCEPTIONAL = 3; //执行过程中被取消 private static final int CANCELLED = 4; //线程执行被中断(**一个瞬时的标记**) private static final int INTERRUPTING = 5; //线程执行被中断的状态 private static final int INTERRUPTED = 6;
  volatile保证了线程执行的状态改变之后会刷新到内存中,被其他线程可见
  如果线程还处于未完成的状态,即 s <= COMPLETING  ,就会进入等待状态,调用awaitDone(false, 0L)  方法 ①get为何阻塞等待?/**  @param timed 若是true则为定时等待,超时后会结束等待,并返回当前状态state  @param nanos 如果是定时等待即第一个入参timed=true的话,会设置对应的等待时长 */ 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);      } }
  详细的注释在代码中,请耐心看一下。
  简单来说,能结束等待的条件只有5个:  完成  被中断  设置定时等待并超时  被取消  抛了其他异常,比如RuntimeException,这里的其他异常既不是中断异常,也不是取消异常
  调用 futureTask.get()  的等待方式有2种,分为定时等待和 不计时等待: timed=true  是定时等待,会创建等待结点q = new WaitNode();  并放在栈顶(队列头部),然后挂起。结束等待的条件(满足任一即可)是【完成】、【被中断】、【被取消】、【抛其他异常】、【超时】 。 timed=false  是不计时等待,创建等待结点后会一直挂起,只有【完成】、【被中断】、【被取消】、【抛其他异常】
  在等待结束之前, LockSupport.park(this);  表示线程会被一直挂起,不再继续无限循环占用CPU。
  解除挂起的条件是 state > COMPLETING  ,然后调用finishCompletion()  方法去让线程解除挂起并回到awaitDone()  做最后一次循环后return state ② 从get中返回结果report(int s)/*正常的计算结果 or 抛出的异常 都会作为outcome*/ private Object outcome; private V report(int s) throws ExecutionException {  Object x = outcome;  //正常完成  if (s == NORMAL)   return (V)x;  //执行的过程中【被取消】  if (s >= CANCELLED)   throw new CancellationException();  /**   这里抛的是执行过程中发生的其他异常,既不是【中断异常】,也不是【被取消异常】   比如发生了RuntimeException之类的就会在这抛  */   throw new ExecutionException((Throwable)x); }
  report(int s)  是执行get()获取结果的最后一步
  看到这可能有朋友晕了,我把get()内部的流程梳理一下:  若要等待计算结果:get() -> awaitDone() -> report(),共3步  不用等待:get() -> report() ,仅2步  四、FutureTask是如何拿到线程执行的结果?
  主要 有赖于FutureTask类内部的Callable接口
  只有Callable接口能拿到线程的返回值,下面来看下FutureTask的构造函数  public class FutureTask implements RunnableFuture {  //执行任务并返回结果  private Callable callable;  public FutureTask(Callable callable) {   if (callable == null)    throw new NullPointerException();   this.callable = callable;   //新建状态   this.state = NEW;  } }
  其实Callable 接口是没法 作为创建线程 new Thread(Runnable target)  的入参的,只有借助FutureTask类才能被线程执行,因为FutureTask实现了Runnable 接口
  有兴趣的可以看一下Future接口的关系图(这里拿了大佬的图,侵删)
  FutureTask类最终实现了Future接口和Runnable接口,可作为 new Thread(Runnable target)  的入参target来创建线程 五、FutureTask可能的执行过程顺利完成 :NEW -> COMPLETING -> NORMAL ,即新建->正在完成 ->正常  NEW -> COMPLETING -> EXCEPTIONAL, 执行过程出现了异常  被取消:NEW -> CANCELLED  NEW -> INTERRUPTING -> INTERRUPTED,新建 ->正在被中断 ->中断完成  六、列举一下FutureTask的特性和应用场景
  特性:  异步执行,可执行多次(通过runAndReset()方法),也可仅执行一次(执行run()即可)  可获取线程执行结果
  应用场景:  长时间运行的任务,包含远程调用的任务  数据量大的查询,划分为多个小查询,每个FutureTask 仅执行一次 的特性能有效避免重复的查询  计算密集型的任务
  来源:blog.csdn.net/qq_44384533/article/details/111920875

绿厂打算抽送智能电视,网友整活不如再附送一套房子OPPO在此前的智美生活发布会上带来了全新的OPPO智能电视系列。而在11月7日,OPPO智美生活官博发布一条微博称想抽一台OPPO智能电视,但又担心你家放不下,怎么办,在线等?,千元真香机首选?OPPOK7x直指双11,尾款人大赞就在11月4日,OPPO正式发布了OPPOK7x,不仅拥有时尚靓丽的外观硬核5G,还拥有90Hz刷新率和超能续航,新机仅售价1499元,在发布后便引发了众多网友的热情关注。现在正处外贸网站设计的小心机!全撂这了1网站的配色每一个行业和产品领域,都有其独特的主流模板和色系。这种颜色背景,能够不断强化产品或者服务在客户心中的印象。我们看很多网站的设计并不美观,但是在行内客户看来,它又极其地道加入WhatsApp群聊,更多精准潜客等你挖掘WhatsApp重要通知WhatsApp新政策推至5月15日生效,逾期将无法使用完整功能本月WhatsApp在官网发布了一篇与隐私和安全有关的文章,旨在敦促用户在5月15日前接受最iPhone12mini翻车?使用一周后,这几点吐槽最多iPhone12mini推出后,许多人对这款手机的外观非常好奇。众所周知,iPhone12如今也很流行,迷你机型也引起了很多人的关注。它的质量直接影响到市场上iPhone的评估,许全球搜受邀出席国企创新行新媒体品牌营销策略分享会全球化的今天,企业之间的比拼,无不反映出企业品牌之间的竞争。中国企业品牌走出去,尤其是国有企业在海外打造自主品牌,通过品牌扩大自己在国际的影响力,成为中国国有企业负责人关心的话题。72的企业高管表示,社交媒体会直接影响采购决策SproutSocial发布了最新的社交媒体报告72的高管表示,他们的公司利用社交媒体的数据和见解来做出企业决策。85的受访者认为,未来社交媒体数据将是商业情报的主要来源。51的受激流更需勇进!看国内口罩制造龙头如何打开国际市场知名度作为国内市场占有率为35的呼吸防护用品研发制造龙头企业,建德市朝美日化有限公司迅速响应新型冠状病毒肺炎疫情肆虐的市场需求,第一时间召回员工来厂安排过年期间,除夕只有半天休息,其余时面对亚马逊封店风波,跨境电商企业应如何自救?亚马逊封店事件从今年5月份开始,不断有亚马逊大卖店铺被封停7月6日,340个亚马逊账号惨遭封杀,涉及冻结资金高达1。3亿元据深圳市跨境电子商务协会6月份统计,在过去的两个多月时间,揭秘真相!广告主为什么看不到自己的Google广告?哈哈哈这绝对不是骗局,也是很多企业会遇见的问题在谷歌上搜索不到自己的广告!这是为什么呢?让我们一一解答,首先,我们要明确,搜索不到自己的广告,有多方面的影响因素,以下会罗列大家经常外贸企业出海缺什么?缺流量啊昨日,微信屏蔽网易性格主导色测试分享引发网友的热议。知乎上相关话题讨论究竟网易云的操作违反了微信的制度,还是平台的刻意垄断呢?从不同角度分析,得到的答案会不一样。不过反观外贸行业,
芯片损失超万亿?美不得不找台阶下,但华为却拉出两个小狼崽现如今,我国的科技领域是越来越壮大,几乎影响了美国科技霸主的地位,于是美国使出阴招,给中国的科技设下障碍。因此,这些障碍起到了连锁作用。现如今华为是我国唯一一家在世界领域崭露头角的孟晚舟回国,华为宣布向美国系统宣战,华为欧拉操作系统横空出世9月25日,一个让我们中国人非常高兴欢呼的消息传来,孟晚舟女士回国啦。相信孟晚舟女士是因为什么被拘留的,而且拘留的原因也是让人愤怒。2018年12月1日,美国和加拿大相互勾结,将在win10应用商店出现0x80072f78的解决方法有一位深度技术win10专业版系统的用户,很喜欢在win10应用商店中下载里面软件和各种游戏,但是刚刚他在电脑上想要使用win10应用商店的时候,却出现打不开并提示错误代码0x80win7sp1电脑远程桌面连接很慢的解决方法有不少深度技术的小伙伴在使用win7sp1系统的时候,都会使用到电脑自带的远程桌面连接功能。但有一位小伙伴却发现他的win7远程桌面连接其他电脑的时候连接很慢的情况,下面,深度系统win10正式版系统电脑卡怎么办应该有不少深度系统的电脑用户,都遇到过电脑使用久了出现卡顿,反应慢的问题吧,其实,一般都是因为C盘中有许多没有用的文件,占用大量内存空间导致的。那针对win10正式版系统电脑卡怎么远离渣酒,教你读懂八大葡萄酒评分标准,选择高性价比葡萄酒前言大家好,我是小猴。作为一名美食博主,日常经常会研究关于美食的相关知识,在每一次购买前做到对商品的全面掌握,这样在面对种类品牌繁多的商品时才能够做到胸有成竹。关于葡萄酒,我从小就2021年上半年最佳的XboxSeriesX显示器推荐XBX如果您拥有XboxSeriesX并且更喜欢在显示器上玩游戏,那么有很多选项可供选择,尤其是当您正在寻找高刷新率时。但是,目前市场上高刷新率的4k显示器并不多,这意味着您可能不2021上半年3台最佳的PS5电视2021上半年3台最佳的PS5电视随着今年索尼的PS5游戏机发布,PS5的性能升级带来的画面升级,更带来了高刷新率的支持,这些功能提供了愉快的游戏体验。那么如何选择一台合适的高刷新腾讯2021上半年财报低调公布员工人均月薪7。85万8月18日,腾讯低调发布了2021年二季度财报,公布的数据引起了众多讨论。财报中显示,上半年,腾讯总收入2735。62亿元,同比增长23净利润903。54亿元,同比增长46,平均每Python登顶,Java和C辉煌不再?TIOBE10月编程语言排行榜出炉十一假期刚刚结束,你从长假中缓过神儿来了吗?假期间,TIOBE10月编程语言榜单也新鲜出炉,不得不说,这一次大家真的见证了历史性的一刻TIOBE榜单创建至今已经经历了二十余年,排行win7ghost纯净版物理内存过高怎么办相信深度技术用户都知道内存的大小来决定是安装win732位旗舰版还是win764位系统,比如4G以上的内存我们需要安装windows7纯净版64位的才能完美地支持,但近日有使用wi