Java vertx executeBlocking不同的行为

Java vertx executeBlocking不同的行为,java,multithreading,asynchronous,vert.x,Java,Multithreading,Asynchronous,Vert.x,我正在试验vertx ExecuteBlock,以模拟我所遵循的实时场景 vertx.setPeriodic(1000, id ->{ counter += 1; LOGGER.info("invoked method {} ",counter); vertx.executeBlocking(future -> { int counterFinal = counter; String result = service.block

我正在试验vertx ExecuteBlock,以模拟我所遵循的实时场景

vertx.setPeriodic(1000, id ->{
    counter += 1;
    LOGGER.info("invoked method {} ",counter);
    vertx.executeBlocking(future -> {
        int counterFinal = counter;
        String result = service.blockingMethod("cycle "+counterFinal+" executed");
        future.complete(result);
    }, res -> {
        LOGGER.info(String.format("The result is: %s", res.result()));
    });
阻塞方法非常简单

public String blockingMethod(String result){
    block(2);
    return result;
}
这就是结果

07:50:27.742 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.AsyncExperimentalVerticle - invoked method 1 
07:50:28.742 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.AsyncExperimentalVerticle - invoked method 2 
07:50:29.740 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.AsyncExperimentalVerticle - invoked method 3 
07:50:29.764 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.AsyncExperimentalVerticle - The result is: cycle 1 executed
07:50:30.739 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.AsyncExperimentalVerticle - invoked method 4 
07:50:31.739 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.AsyncExperimentalVerticle - invoked method 5 
07:50:31.773 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.AsyncExperimentalVerticle - The result is: cycle 3 executed
07:50:32.751 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.AsyncExperimentalVerticle - invoked method 6 
07:50:33.748 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.AsyncExperimentalVerticle - invoked method 7 
07:50:33.789 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.AsyncExperimentalVerticle - The result is: cycle 5 executed
显然,由于延迟设置为2秒,它平均错过了两个事件。 然后我将阻塞方法包装在一个类中,然后按照以下方式执行

vertx.setPeriodic(1000, id ->{
    counter++;
    LOGGER.info("invoked method {} ",counter);
    service.wrapperMethod("Hello", counter, new Handler<AsyncClass>() {
        @Override
        public void handle(AsyncClass event) {
            vertx.executeBlocking(future -> {
                String result = event.result();
                future.complete(result);
            }, res -> {
                LOGGER.info(String.format("The result is: %s", res.result()));
            });
        }
    });
});
现在我看到的是异步执行,没有遗漏一个事件。我找不到可能的解释。 即使在包装器方法中,如果我给出n秒的延迟,它也会错过预期的事件

有人请帮我理解这种行为

更新1:

对于第二种场景,
AsyncClass
的结构如下所示

public class AsyncClass {

    private static final Logger LOGGER = LoggerFactory.getLogger(AsyncClass.class);

    private String input;
    private String cycle;

    public AsyncClass(String input, String cycle) {
        this.input = input;
        this.cycle = cycle;
    }

    public String result(){
        LOGGER.info("Invoking method inside AsyncClass class");
        block(2);
        return input+" world of cycle "+cycle;
    }

    private void block(int pauseLimitInSecond){
        try {
            TimeUnit.SECONDS.sleep(pauseLimitInSecond);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            LOGGER.error("exception - > ", e);
        }
    }
}

您使用的
executeBlocking
可确保按顺序(一个接一个)执行阻塞任务

因此,当执行第二个阻塞任务时(两秒钟后),
计数器
变量已经增加了两次。因此出现了
1
3
5
系列


在另一次尝试包装类时,在调用
executeBlocking
之前捕获
计数器
变量值。因此,当执行阻塞任务时,您会得到预期的值。

您使用的
executeBlocking
确保阻塞任务按顺序(一个接一个)执行

因此,当执行第二个阻塞任务时(两秒钟后),
计数器
变量已经增加了两次。因此出现了
1
3
5
系列


在另一次尝试包装类时,在调用
executeBlocking
之前捕获
计数器
变量值。因此,当执行阻塞任务时,您会得到预期的值。

观察到的行为是由于捕获外部类引用(
this
)的位置造成的

外部类实例变量
counter
将在计算Lambda body表达式时更改其值(比初始值增加
1
),这会产生意外行为的错觉

保持相同的程序顺序,您可以使用
处理程序
实现替换Lambda表达式体,其中
计数器
外部实例变量存储在另一个实例变量中,该实例变量将在处理程序执行体中使用:

private static final class BlockingHandler实现处理程序{
私人最终封锁服务;
专用最终整数计数器;
公共封锁管理器(int柜台、YourBlockingService服务){
this.counter=计数器;
服务=服务;
}
@凌驾
公共无效句柄(未来事件){
字符串结果=service.blockingMethod(“cycle”+this.counter+“executed”,2);
事件。完成(结果);
}
}
您的垂直代码将如下所示:

this.vertx.setPeriodic(
1000,
id->{
计数器+=1;
info(“调用的方法{}”,计数器);
vertx.executeBlock(
新的YourBlockingHandler(this.counter,this.service),
res->LOGGER.info(String.format(“结果是:%s”,res.result()))
);
}
);

要继续,所提到的行为只与闭包语义有关,与Vert.x内部无关。

观察到的行为是由于捕获外部类引用(
this
)的位置造成的

外部类实例变量
counter
将在计算Lambda body表达式时更改其值(比初始值增加
1
),这会产生意外行为的错觉

保持相同的程序顺序,您可以使用
处理程序
实现替换Lambda表达式体,其中
计数器
外部实例变量存储在另一个实例变量中,该实例变量将在处理程序执行体中使用:

private static final class BlockingHandler实现处理程序{
私人最终封锁服务;
专用最终整数计数器;
公共封锁管理器(int柜台、YourBlockingService服务){
this.counter=计数器;
服务=服务;
}
@凌驾
公共无效句柄(未来事件){
字符串结果=service.blockingMethod(“cycle”+this.counter+“executed”,2);
事件。完成(结果);
}
}
您的垂直代码将如下所示:

this.vertx.setPeriodic(
1000,
id->{
计数器+=1;
info(“调用的方法{}”,计数器);
vertx.executeBlock(
新的YourBlockingHandler(this.counter,this.service),
res->LOGGER.info(String.format(“结果是:%s”,res.result()))
);
}
);

要继续,所提到的行为只与闭包语义有关,与Vert.x内部无关。

在哪里记录了AsyncClass类消息内调用方法?第二种情况下的实际阻塞方法
fun result()
AsyncClass
内。我已经用更多的细节更新了我的问题。现在请查看。调用AsyncClass类消息中的方法记录在哪里?第二种情况下的实际阻塞方法
fun result()
AsyncClass
中。我已经用更多的细节更新了我的问题。现在请看。
08:08:27.358 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.TestVerticle2 - invoked method 1 
08:08:27.368 [vert.x-worker-thread-0] INFO lab.async.base.support.AsyncClass - Invoking method inside AsyncClass class
08:08:28.338 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.TestVerticle2 - invoked method 2 
08:08:29.345 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.TestVerticle2 - invoked method 3 
08:08:29.384 [vert.x-worker-thread-0] INFO lab.async.base.support.AsyncClass - Invoking method inside AsyncClass class
08:08:29.386 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.TestVerticle2 - The result is: Hello world of cycle 1
08:08:30.347 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.TestVerticle2 - invoked method 4 
08:08:31.351 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.TestVerticle2 - invoked method 5 
08:08:31.391 [vert.x-worker-thread-0] INFO lab.async.base.support.AsyncClass - Invoking method inside AsyncClass class
08:08:31.391 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.TestVerticle2 - The result is: Hello world of cycle 2
08:08:32.341 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.TestVerticle2 - invoked method 6 
08:08:33.343 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.TestVerticle2 - invoked method 7 
08:08:33.396 [vert.x-worker-thread-0] INFO lab.async.base.support.AsyncClass - Invoking method inside AsyncClass class
08:08:33.397 [vert.x-eventloop-thread-0] INFO lab.async.base.verticle.TestVerticle2 - The result is: Hello world of cycle 3
public class AsyncClass {

    private static final Logger LOGGER = LoggerFactory.getLogger(AsyncClass.class);

    private String input;
    private String cycle;

    public AsyncClass(String input, String cycle) {
        this.input = input;
        this.cycle = cycle;
    }

    public String result(){
        LOGGER.info("Invoking method inside AsyncClass class");
        block(2);
        return input+" world of cycle "+cycle;
    }

    private void block(int pauseLimitInSecond){
        try {
            TimeUnit.SECONDS.sleep(pauseLimitInSecond);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            LOGGER.error("exception - > ", e);
        }
    }
}