java - 仅在 ExecutorService 中提交任务时设置变量值

标签 java concurrency executorservice java-threads

使用ExecutorService我提交了一批任务,任务有一个时间变量,即 GENERAL_TIME他们之间分享。我想设置GENERAL_TIME的值就在提交任务之前。这是代码:

ExecutorService executor = Executors.newWorkStealingPool();
    ArrayList<Callable<Boolean>> callables = new ArrayList<>();
    long GENERAL_TIME = 0;
    for (String i : host.getHosts()){
        callables.add(
                () -> {
                    ESBRun.monitorOSMetrics(
                            db, COMPONNENT_TYPE, GENERAL_TIME, metric, ssh, i
                    );
                    return true;
                }
    }
    GENERAL_TIME = System.currentTimeMillis();
    executor.invokeAll(callables)
            .stream()
            .map(future -> {
                try {
                    return future.get();
                }
                catch (Exception e) {
                    throw new IllegalStateException(e);
                }
            });
}

但是有错误

variable used in lambda should be final or effectively final java

我该如何解决这个问题?

最佳答案

您的变量是在堆栈上定义的,该堆栈通常会在方法退出后被垃圾收集。但是,使用 lambda 中的值需要 Java 共享闭包中的值,这要求它是最终的或有效最终的(不被共享的任何代码修改)。因此,任何要在线程之间保持可变的值都必须包装到一个实例中,该实例本身是最终的或实际上是最终的。

实现此目的的最简单且线程安全的方法是使用 java.util.concurrent.atomic 中的类,在您的情况下是 AtomicLong。变量本身实际上是最终的,或者可以声明为最终的,但可以在任何 lambda 和线程中设置(和读取)该值:

// declaration
final AtomicLong generalTime = new AtomicLong(0);

// usage acr
generalTime.set(System.currentTimeMillis()));
generalTime.get();

关于java - 仅在 ExecutorService 中提交任务时设置变量值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49087790/

相关文章:

java - scan.hasNext 应该为真时为假

mysql - 循环中Mysql表消费者进程的行轮换

java - 如何为 ScheduledExecutor 服务提供最大时间来继续启动新线程?

java - ExecutorService 类型中的方法 invokeAll 不适用于参数错误

java - 覆盖线程池中线程的中断方法

java - Java 最高效的 JSF 1.2 导航

Java:调整图像大小不起作用

java - 我的服务器应该同时使用 TCP 和 UDP 吗?

java - long 和 double 赋值不是原子的——这有什么关系?

java - 使用 ScheduledExecutorService 的计划任务?一个好主意?