想请问大家关于 completablefuture 中参数传递线程安全问题。 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
golangLover
V2EX    Java

想请问大家关于 completablefuture 中参数传递线程安全问题。

  •  
  •   golangLover 2021 年 10 月 22 日 1963 次点击
    这是一个创建于 1645 天前的主题,其中的信息可能已经有所发展或是发生改变。

    搜了 stackoverflow 似乎没有人提过这个问题,因为我也是迫于公司要初学 java,大家见笑了。

    这段代码主要想大家帮忙看看 iterate 函数在 for 循环会不会有线程安全的问题。

    主要的问题是:

    不肯定 iterate 函数 在 for 循环之中,intA 以及 uuid 会不会有线程安全的问题。 1: 就是 thenApply 里面的 intA 与 supplyAsync 里面的是否一致。 2: 也不肯定这传入的参数 intA 与 uuid, 与 thenApply 里面拿到的会不会都是同一组参数。也就是会不会因为循环而导致 uuid 是拿到较为新的情况,而 intA 比较旧?导致计算结果不合理。

    我原本想把结果 print 出来测试一下,但是又无从下手,因为这如果真的有线程安全问题也不是 debugger 能看的出来。

    先感谢大家的赐教。谢谢

    import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import java.util.stream.IntStream; public class Test { public static void main(String[] args) { new Test().run(); } private void run() { List<Integer> list = IntStream.range(1,10000).boxed().collect(Collectors.toList()); List<CompletableFuture<Integer>> cfList = new ArrayList<>(); for (Integer intA: list) { String uuid = UUID.randomUUID().toString(); CompletableFuture<Integer> future = this.iterate(intA,uuid); cfList.add(future); } CompletableFuture<List<Integer>> resultCf = this.allOf(cfList); resultCf.join(); } private CompletableFuture<Integer> iterate(Integer intA, String uuid) { return CompletableFuture.supplyAsync(()->{ // 假设需要用到第一个参数,然后返回 return intA+2; }).thenApply((req)->{ return intA+5; }).thenApply((value)->{ // 假设这个耗时操作要用到第一个参数以及第二个参数。 // 不肯定 在 for 循环之中,intA 以及 uuid 会不会有线程安全的问题。 // 1: 就是 thenApply 里面的 intA 与 supplyAsync 里面的是否一致。 // 2: 也不肯定这传入的参数 intA 与 uuid, 与 thenApply 里面拿到的会不会都是同一组参数。 // 也就是会不会因为循环而导致 uuid 是拿到较为新的情况,而 intA 比较旧?导致计算结果不合理。 System.out.println(uuid); return 3+value; }); } // 等待 list 完毕 private <T> CompletableFuture<List<T>> allOf(List<CompletableFuture<T>> futuresList) { CompletableFuture<Void> allFuturesResult = CompletableFuture.allOf(futuresList.toArray(new CompletableFuture[0])); return allFuturesResult.thenApply(v -> futuresList.stream(). map(CompletableFuture::join). collect(Collectors.toList()) ); } } 
    8 条回复    2021-10-25 22:18:29 +08:00
    hingbong
        1
    hingbong  
       2021 年 10 月 22 日
    lambda 里面拿外面的变量都是栈里面而且还是 final 的吧,应该没问题
    0Vincent0Zhang0
        2
    0Vincent0Zhang0  
       2021 年 10 月 22 日 via Android
    这个场景下,没有线程安全问题。
    因为:
    1.iterate 方法里没有“修改”intA (给 intA 赋值不算“修改”)
    2.list 里面没有相同的 Integer
    chendy
        3
    chendy  
       2021 年 10 月 22 日
    貌似全程没看到会被多个线程访问到的变量,所以是不存在线程安全问题
    thenApply 是上一步执行完了执行下一步,是同步的,所以最后一个 thenApply 里能达到的 value 就是最新的
    另外不存在 intA 比较旧的问题,intA 全程没有被重新赋值过,一直就是初始值
    wangyu17455
        4
    wangyu17455  
       2021 年 10 月 23 日
    lambda 里面访问外部的临时变量,是通过构造函数传参实现的,这也是为什么不能在 lamda 和匿名内部类里面修改外部临时变量的值,两者只通过运行构造函数同步一次。所以在 computablefuture 里面虽然运行顺序由你的代码指定,但是你传入的三个 lambda 是在同一次循环内部创建完成的。
    golangLover
        5
    golangLover  
    OP
       2021 年 10 月 24 日
    @hingbong @0Vincent0Zhang0 @chendy @wangyu17455 感谢各位大佬的赐教
    golangLover
        6
    golangLover  
    OP
       2021 年 10 月 24 日
    @wangyu17455 另外想请问这个 “lambda 只通过运行构造函数同步一次” 和 “你传入的三个 lambda 是在同一次循环内部创建完成的” 这里的出处能在哪里找到。我觉得自己对这个了解不是太深入。搜了 lambda 串联好像没提到这个。谢谢
    wangyu17455
        7
    wangyu17455  
       2021 年 10 月 25 日
    “只通过构造函数同步一次“反编译就可以看到, “你传入的三个 lambda 是在同一次循环内部创建完成的” 把 lambda 当做匿名内部类理解就行,匿名内部类实际上就是正常类的语法糖,()->{xx}在编译的时候就被当做 new X(y)处理
    golangLover
        8
    golangLover  
    OP
       2021 年 10 月 25 日
    @wangyu17455 好的,谢谢你!
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     876 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 53ms UTC 20:55 PVG 04:55 LAX 13:55 JFK 16:55
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86