Você pode vincular objetos mutáveis a scoped values?
Sim, mas eu acho que você não deveria.
Question
Você pode vincular objetos mutáveis a scoped values?
Less Short Answer
Mutabilidade sempre traz problemas de race condition. A única forma de ter certeza de que não existe nenhuma race condition possível no seu código é quando você tem uma única thread executando tudo, e isso também vale para scoped values.
Scoped Values Não São Sobre Threads
Scoped values não têm relação com multithreading. Você chama uma tarefa, modelada por um Runnable ou um Callable, e define um binding para uma variável scoped value que fica disponível no escopo dessa tarefa. Se você tem certeza de que nenhuma thread é criada nessa tarefa, então vincular um valor mutável é seguro. Se não, você precisa gerenciar as possíveis race conditions por conta própria.
javastatic final ScopedValue<List<String>> LOG = ScopedValue.newInstance();
// uma única thread: a lista mutável nunca é compartilhada, então é seguro
ScopedValue.where(LOG, new ArrayList<>()).run(() -> {
LOG.get().add("start");
LOG.get().add("end");
});Onde Quebra
Subtarefas criadas com fork em um StructuredTaskScope enxergam o binding do pai. Com um valor mutável, todas compartilham o mesmo objeto, a partir de threads diferentes:
javaScopedValue.where(LOG, new ArrayList<>()).run(() -> {
try (var scope = StructuredTaskScope.open()) {
for (int i = 0; i < 1_000; i++) {
int n = i;
scope.fork(() -> LOG.get().add("task " + n)); // ArrayList não é thread-safe
}
scope.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(LOG.get().size()); // pode imprimir menos de 1000, ou lançar exceção
});Vincular um valor imutável resolve o problema: todas as subtarefas leem o mesmo valor, e ninguém consegue alterá-lo.
javastatic final ScopedValue<String> REQUEST_ID = ScopedValue.newInstance();
ScopedValue.where(REQUEST_ID, "req-42").run(() -> {
// seguro ler de qualquer subtarefa: uma String não muda
});One Last Word
Fique seguro, fique longe de vincular valores mutáveis. Não é porque você pode fazer algo que você deveria fazer.