TGViewer
Spring АйО Spring АйО @spring_aio · 11K subscribers
Post #115 2.74K
🖥 Scoped Values в Java (Часть 1)

Судя по реакциям на предыдущих постах про JEP, они вам нравятся, так что продолжаем разбирать свежые JEP'ы.

Представим себе небольшой веб-фреймворк, который обрабатывает HTTP-запросы. Фреймворк создает контекст для каждого запроса и передает его через методы:


@Override
public void handle(Request request, Response response) {
var userInfo = readUserInfo();
}

private UserInfo readUserInfo() {
return (UserInfo) framework.readKey("userInfo", context);
}


Ранее для передачи контекста использовались переменные типа ThreadLocal:


private final static ThreadLocal<FrameworkContext> CONTEXT = new ThreadLocal<>();

void serve(Request request, Response response) {
var context = createContext(request);
CONTEXT.set(context);
Application.handle(request, response);
}

public PersistedObject readKey(String key) {
var context = CONTEXT.get();
var db = getDBConnection(context);
db.readKey(key);
}


Scoped Values API впервые был представлен в JDK 20 и прошел несколько итераций и улучшений в последующих версиях JDK (JEP 429, JEP 446, JEP 464, JEP 481). Scoped Values представляют собой новый механизм для передачи неизменяемых данных между методами в одном потоке и между дочерними потоками. Этот механизм проще в использовании по сравнению с ThreadLocal и обладает меньшими затратами по времени и памяти.

У подхода, использующего ThreadLocal, есть несколько недостатков:

1. Неограниченная изменяемость — переменные могут изменяться в любое время любым кодом в потоке
2. Неограниченное время жизни — переменные могут существовать дольше, чем необходимо, что может приводить к утечкам памяти
3. Высокая стоимость наследования — при создании дочерних потоков переменные должны копироваться, что увеличивает затраты по памяти

Scoped Values позволяют избежать этих проблем, обеспечивая одноразовую запись и ограниченное время жизни значений:


final static ScopedValue<FrameworkContext> CONTEXT = ScopedValue.newInstance();

void serve(Request request, Response response) {
var context = createContext(request);
ScopedValue.runWhere(CONTEXT, context, () -> Application.handle(request, response));
}

public PersistedObject readKey(String key) {
var context = CONTEXT.get();
var db = getDBConnection(context);
db.readKey(key);
}


В данном случае метод ScopedValue.runWhere связывает значение с текущим потоком на время выполнения лямбда-выражения, после чего связь уничтожается, что улучшает производительность и безопасность кода.

В 23 версии Java фича будет пересмотрена повторно с одним изменением: тип параметра операции метода ScopedValue.callWhere будет являться новым функциональным интерфейсом, который позволит компилятору Java делать вывод о том, может ли быть выброшено проверяемое исключение. Подробнее про ScopedValue.callWhere и улучшения, связанные с ним, поговорим во второй части.

Ставьте 🔥 если хотите вторую часть!

#Java #JEP
  • 🔥 59
  • 👍 9
  • ❤ 2
More from @spring_aio
  1. Oct 11, 2026🎬 Записи докладов с JPoint 2026 уже в открытом доступе JUG Ru Group выложили записи с про…
  2. Oct 9, 2026👩‍💻 Kotlin получил почти настоящие статики Начиная с Kotlin 2.5.0-Beta1 можно эксперимен…
  3. Oct 8, 2026🍃 Spring Boot ломает совместимость, G1 тормозит микросервисы, Java долго релизит фичи | S…
  4. Oct 6, 2026👩‍💻 Spring Config Import без магии У наших друзей из Axelix вышла статья о том, как Spri…
  5. Oct 5, 2026🥲 В Java 27 TLS научился переживать квантовую атаку При установке HTTPS-соединения клиент…
  6. Oct 3, 2026⚡️⚡️Строки кода стремятся подешеветь до цены токена. Что остается ценным? Про это — трек «…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →