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

Java 仅在ExecutorService中提交任务时设置变量值,java,concurrency,executorservice,java-threads,Java,Concurrency,Executorservice,Java Threads,使用ExecutorService我提交了一批任务,任务有一个时间变量,即GENERAL\u time它们之间的共享。我想在提交任务之前设置GENERAL\u TIME的值。代码如下: ExecutorService executor = Executors.newWorkStealingPool(); ArrayList<Callable<Boolean>> callables = new ArrayList<>(); long GENERA

使用
ExecutorService
我提交了一批任务,任务有一个时间变量,即
GENERAL\u time
它们之间的共享。我想在提交任务之前设置
GENERAL\u 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);
                }
            });
}

如何解决这个问题?

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

实现这一点的最简单也是线程安全的方法是使用
java.util.concurrent.atomic
中的类,在您的例子中是
AtomicLong
。变量本身实际上是final或可以声明为final,但可以在任何lambda和线程中设置(和读取)该值:

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

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

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

实现这一点的最简单也是线程安全的方法是使用
java.util.concurrent.atomic
中的类,在您的例子中是
AtomicLong
。变量本身实际上是final或可以声明为final,但可以在任何lambda和线程中设置(和读取)该值:

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

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

导致错误的代码在哪里?此语句
GENERAL\u TIME=System.currentTimeMillis()不在lambda表达式中,不能在后期编辑时导致编译错误。我调用一个使用
GENERAL\u TIMESTAMP
作为参数的函数。该行导致so call error.Thx。
GENERAL\u TIME
的用法不清楚。您打算对所有线程的执行时间进行计时吗?我很确定lambda的设计不是这样的。常规时间是在创建lambda时捕获的(
callables.add()
),规范设计阻止任何其他类型的捕获。导致该错误的代码在哪里?此语句
GENERAL\u TIME=System.currentTimeMillis()不在lambda表达式中,不能在后期编辑时导致编译错误。我调用一个使用
GENERAL\u TIMESTAMP
作为参数的函数。该行导致so call error.Thx。
GENERAL\u TIME
的用法不清楚。您打算对所有线程的执行时间进行计时吗?我很确定lambda的设计不是这样的。一般时间是在创建lambda时捕获的(
callables.add()
),规范设计防止任何其他类型的捕获。这似乎是一个很好的解决方案,只需要为OP重新编码一点工作。我经常使用相同的技术在反应式代码和lambda之间共享值。我倾向于使用不可变对象在线程之间共享信息。当从其他语言改编代码和算法时,您的答案似乎是一个很好的通用模式。这似乎是一个很好的解决方案,只需为OP重新编码一点工作。我经常使用相同的技术在反应式代码和lambdas之间共享值。我倾向于使用不可变对象在线程之间共享信息。当从其他语言改编代码和算法时,您的答案似乎是一个很好的通用模式。