lambda 和新线程中递增值的值不正确

问题描述 投票:0回答:1

我创建了 10 个并行网络请求。 我需要了解所有这些何时完成。

我尝试通过 AtomicIntegersynchronized 块来做到这一点。但这没有帮助。

hostInfoList 的大小 = 10。

这里片段:

AtomicInteger countOfResponse = new AtomicInteger(0);
LOGGER.info("myMethod: hostInfoList_size  = {}", hostInfoList.size());
for (HostInfo hostInfo : hostInfoList) {
    new Thread(() -> {
        ErrorDetails errorDetails = new ErrorDetails();
        XML response = null;
        try {
            LOGGER.info("");
            response = execute_network_request(); // run network request
            LOGGER.info("myMethod: before_inc_count = {}", countOfResponse.get());
            synchronized (this) {
                countOfResponse.incrementAndGet();
            }
            LOGGER.info("myMethod:after_inc_count = {}", countOfResponse.get());
        } catch (Exception e) {
            errorDetails.setDetails(e.getMessage());
        } finally {
            LOGGER.info("myMethod: finally")
        }
    }).start();
} 

这里记录:

2024-02-15 13:28:08.558 INFO  [MyClass:Thread-275] myMethod: before_inc_count = 0
2024-02-15 13:28:08.558 INFO  [MyClass:Thread-272] myMethod: before_inc_count = 0
2024-02-15 13:28:08.558 INFO  [MyClass:Thread-275] myMethod: after_inc_count = 2
2024-02-15 13:28:08.558 INFO  [MyClass:Thread-272] myMethod: after_inc_count = 2
2024-02-15 13:28:08.559 INFO  [MyClass:Thread-275] myMethod: finally
2024-02-15 13:28:08.559 INFO  [MyClass:Thread-272] myMethod: finally
2024-02-15 13:28:08.559 INFO  [MyClass:Thread-274] myMethod: before_inc_count = 2
2024-02-15 13:28:08.559 INFO  [MyClass:Thread-274] myMethod:after_inc_count = 3
2024-02-15 13:28:08.559 INFO  [MyClass:Thread-271] myMethod: before_inc_count = 3
2024-02-15 13:28:08.559 INFO  [MyClass:Thread-274] myMethod: finally
2024-02-15 13:28:08.559 INFO  [MyClass:Thread-273] myMethod: before_inc_count = 3
2024-02-15 13:28:08.559 INFO  [MyClass:Thread-271] myMethod:after_inc_count = 4
2024-02-15 13:28:08.560 INFO  [MyClass:Thread-273] myMethod:after_inc_count = 5
2024-02-15 13:28:08.560 INFO  [MyClass:Thread-271] myMethod: finally
2024-02-15 13:28:08.560 INFO  [MyClass:Thread-273] myMethod: finally
2024-02-15 13:28:08.560 INFO  [MyClass:Thread-276] myMethod: before_inc_count = 5
2024-02-15 13:28:08.560 INFO  [MyClass:Thread-276] myMethod:after_inc_count = 6
2024-02-15 13:28:08.560 INFO  [MyClass:Thread-276] myMethod: finally
2024-02-15 13:28:08.562 INFO  [MyClass:Thread-277] myMethod: before_inc_count = 6
2024-02-15 13:28:08.562 INFO  [MyClass:Thread-277] myMethod:after_inc_count = 7
2024-02-15 13:28:08.562 INFO  [MyClass:Thread-277] myMethod: finally
2024-02-15 13:28:08.562 INFO  [MyClass:Thread-278] myMethod: before_inc_count = 7
2024-02-15 13:28:08.562 INFO  [MyClass:Thread-278] myMethod:after_inc_count = 8
2024-02-15 13:28:08.562 INFO  [MyClass:Thread-278] myMethod: finally
2024-02-15 13:28:08.563 INFO  [MyClass:Thread-279] myMethod: before_inc_count = 8
2024-02-15 13:28:08.563 INFO  [MyClass:Thread-279] myMethod:after_inc_count = 9
2024-02-15 13:28:08.563 INFO  [MyClass:Thread-279] myMethod: finally
2024-02-15 13:28:08.564 INFO  [MyClass:Thread-280] myMethod: before_inc_count = 9
2024-02-15 13:28:08.564 INFO  [MyClass:Thread-280] myMethod:after_inc_count = 10
2024-02-15 13:28:08.564 INFO  [MyClass:Thread-280] myMethod: finally

如您所见,before_inc_count = 0,然后after_inc_count = 2

但是 after_inc_count = 1 在哪里?

java synchronization atomicinteger
1个回答
0
投票

AtomicInteger
只是每个方法调用的原子。如果您对其进行多个方法调用,则每个方法调用都是原子的(并保证可见性),但不能保证对方法的调用不会在线程之间交错。

LOGGER.info("myMethod: before_inc_count = {}", countOfResponse.get()); synchronized (this) { countOfResponse.incrementAndGet(); } LOGGER.info("myMethod:after_inc_count = {}", countOfResponse.get());
这里有 3 个方法调用。线程之间不保证顺序。

要以原子方式执行此操作,您根本不需要同步块:

int valueBefore; LOGGER.info("myMethod: before_inc_count = {}", valueBefore = countOfResponse.getAndIncrement()); LOGGER.info("myMethod:after_inc_count = {}", valueBefore + 1);
但请注意,对 

LOGGER.info

 的调用不是原子的,因此可能仍会在线程之间交错,因此消息可能不会按升序显示。

此外,即使单次调用

LOGGER.info

 也会涉及调用 
getAndIncrement
 方法,因此即使只有第一条日志消息,您也可能会在线程之间交错。

您可以通过将日志行包装在同步块中来避免这种情况;但老实说,在同步块中访问

AtomicInteger

 是更深层次问题的一个指标。

© www.soinside.com 2019 - 2024. All rights reserved.