当前位置: 首页 > 知识库问答 >
问题:

具有完全未来的意外行为

司空坚
2023-03-14

我试图用async CompletableFuture创建一个简单的示例,但我看到了一些奇怪的行为。我的想法是启动两个异步未来,一个在设定时间后激活布尔标志,另一个轮询该标志,在线程1更改该标志后释放该值。这是我的代码:

package completablefutures;

import java.util.concurrent.CompletableFuture;

public class CFMain throws InterruptedException {

    public static void main(String... args) {
        CF cf = new CF();
        CompletableFuture.supplyAsync(cf::getCompletable).thenRun(() -> System.out.println("Post-future action"));
        CompletableFuture.supplyAsync(cf::doSleep);
        Thread.sleep(10000);
    }
}

而CF类:

package completablefutures;

public class CF {
    private boolean valueIsSafe = false;

    public boolean getCompletable() {
        System.out.println("Fetching completable");
        while(true) {
            if(this.valueIsSafe) {
                System.out.println("Completable fetched");
                return true;
            }
        }
    }

    public boolean doSleep() {
        System.out.println("Started sleeping");
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.valueIsSafe = true;
        System.out.println("Finished sleeping");
        return true;
    }
}

当我让程序运行它的课程时,它会打印以下内容:

获取可完成的

开始睡觉

睡过了

进程已完成,退出代码为0

i、 e.未来永远不会在分配的10秒内完成。这是怎么回事?

共有2个答案

徐绪
2023-03-14

这是因为您没有使用线程安全的数据类型,您可以将代码更改为使用AtomicBoolean以下是使用AtomicBoolean的代码示例:

public class CF {
    private AtomicBoolean  valueIsSafe = new AtomicBoolean (false);

     public boolean getCompletable() {
            System.out.println("Fetching completable");
            while(true) {
                if(this.valueIsSafe.get()) {
                    System.out.println("Completable fetched");
                    return true;
                }
                //System.out.println("doing something");
            }
        }

        public boolean doSleep() {
            System.out.println("Started sleeping");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.valueIsSafe.set(true);
            System.out.println("Finished sleeping");
            return true;
        }
    }
西门庆
2023-03-14

如果要从多个线程访问valueIsSafe,则必须将此变量定义为volatile

private volatile boolean valueIsSafe = false;

使用易失性关键字将阻止线程缓存此值并强制它们在每次访问时读取原始内存

 类似资料:
  • 我正在为给定的主键查询Dynamo DB。主键由两个UUID字段(fieldUUID1、fieldUUID2)组成。对于上面的主键组合和值列表,我有很多查询要执行。为此,我使用异步CompletableFuture和ExecutorService,线程池大小为4。 在所有查询返回结果之后,这是

  • 我试图理解java中完整期货的非阻塞回调性质 有了上面的代码,我总是看到下面看到的输出 线程名称ForkJoinPool.common池工人-1 thenApply Thread name main thenApply Thread name main thenAcceptThread name main Thread name main 这个顺序似乎建议主线程等待所有Futures线程的执行。

  • 我正在使用Android TaskStackBuilder,以便在单击通知时使用预定义的堆栈创建通知。 在应用程序中,我有2项活动: 主活动发射器 活动B 在主活动中,我使用TaskStackBuilder和以下堆栈显示通知:[MainActivity(启动器意图),ActivityB] 当通知显示时,我拉下状态栏并单击通知,然后我看到预期的ActivityB,当单击back按钮时,我也看到预期的

  • 我使用的是SpringBoot和SpringDataJPA,我有一个逻辑,它由3个数据库请求组成,我想并行运行。我想在将来用于此目的。 最后,我需要从5 db查询运行的结果中构建响应对象。 所以我创造了完全未来 那我打算用。与这个未来无关。但我对循环调用有问题。如何重写它以在每个请求中使用callable,我需要从请求中传递值,然后按键排序到map中?

  • 我想用Java 8-9启动线程,使用异步模式,这些是我的类和我的线程: 我有三根线。我的类包含单个方法 按以下方式设置我的%s: 正在创建线程: 最后,我的问题是我如何使用异步模式启动这三个线程。

  • 如何使用5个CompletableFutures异步执行20个可运行任务(或1个任务20次)? 这就是我得到的: 如果我执行这段代码,我可以看到它只运行3次。异步获取():3,然后在1 for()迭代中剩下2 所以,我想做所有20个任务,尽可能异步