본문 바로가기
dev/java

Java Virtual Threads 사용 시 synchronized 주의

by igooo 2024. 6. 4.
728x90

개요

Virtual thread를 synchronized 구문과 함께 사용 시 주의 해야한다.
Java 21 + tomcat + HttpComponents  조합으로 Virtural Therad를 활성화하여 사용하면 요청이 많은 경우 서버가 blocking되는 이슈가 발생할 수 있다.

https://openjdk.org/jeps/444
There are two scenarios in which a virtual thread cannot be unmounted during blocking operations because it is pinned to its carrier:
  1. When it executes code inside a synchronized block or method, or
  2. When it executes a native method or a foreign function.

 

이슈사항

HttpComponents 를 사용하여 API를 급격하게 호출하는 경우 서버가 blocked 되어 HttpRequest가 생성되지 않고 서버가 응답하지 않는 이슈가 발생

HttpComponents에서(orgapache.httpcomponents 4.1.5) Java 21의 Virtual Thread 옵션을 사용하는 경우 Dead Lock 이슈가 보고되어 있고(https://issues.apache.org/ira/projects/HTTPCORE/issues/HTTPCORE-746?flter=allissues), 해당 이슈는 HttpComponents 5.x 버전에서만 해결되어 있다.

public static void park(Object blocker) {
	Thread t = Thread. currentThread();
	setBlocker (t, blocker);
	try {
		if (t.isVirtual ()) {
			VirtualThreads.park();
		} else {
			U.park(false, OL);  // blocked
		}
	} finally {
		setBlocker (t, null);
	}
}
@Override
public E get(final long timeout, final TimeUnit timeUnit) throws InterruptedException, ... {
	for(;;) {
		synchronized (this) {
			try {
				final E entry = entryRef. get () ;
				if (entry != null) {
					return entry;
				}
				if (done.get()) {
					throw new ExecutionException()
                }

 

 

Virtual Thread 사용시 Synchronized 블럭은 성능 저하의 원인이 될 수 있다.

https://openjdk.org/jeps/444
There are two scenarios in which a virtual thread cannot be unmounted during blocking operations because it is pinned to its carrier:
  1. When it executes code inside a synchronized block or method, or
  2. When it executes a native method or a foreign function.
Pinning does not make an application incorrect, but it might hinder its scalability. If a virtual thread performs a blocking operation such as I/O or BlockingQueue.take() while it is pinned, then its carrier and the underlying OS thread are blocked for the duration of the operation. Frequent pinning for long durations can harm the scalability of an application by capturing carriers.

 

Virtual Thread는 대부분의 blocking 작업에 대하여 Virtual Thread를 Platform thread에서 분리하여, Platform thread가 Virtual Thread가 I/O등으로 blocking 되어있는 동안 다른 작업을 할 수 있게 해준다. 하지만 synchroznied block, native 메서드는 Platform thread와 분리되지 못한다.(pinned)

Pinning은 에플리케이션을 부정확하게 만들지 않지만 확장성과 성능을 낮출수 있다.

 

https://spring.io/blog/2022/10/11/embracing-virtual-threads

Mitigating Limitations
Our team has been experimenting with Virtual Threads since they were called Fibers. Since then and still with the release of Java 19, a limitation was prevalent, leading to Platform Thread pinning, effectively reducing concurrency when using synchronized. The use of synchronized code blocks is not in of itself a problem; only when those blocks contain blocking code, generally speaking I/O operations. These arrangements can be problematic as carrier Platform Threads are a limited resource and Platform Thread pinning can lead to application performance degradation when running code on Virtual Threads without careful inspection of the workload. In fact, the same blocking code in synchronized blocks can lead to performance issues even without Virtual Threads.
Spring Framework makes a lot of use of synchronized to implement locking, mostly around local data structures. Over the years, before Virtual Threads were available, we have revised synchronized blocks which might potentially interact with third-party resources, removing lock contention in highly concurrent applications. So Spring is in pretty good shape already owing to its large community and extensive feedback from existing concurrent applications. On the path to becoming the best possible citizen in a Virtual Thread scenario, we will further revisit synchronized usage in the context of I/O or other blocking code to avoid Platform Thread pinning in hot code paths so that your application can get the most out of Project Loom.

 

 

참고

 

'dev > java' 카테고리의 다른 글

Java - ReentrantLock  (0) 2024.07.19
Generational ZGC in Java 21  (0) 2024.07.02
Virtual Threads  (0) 2024.06.02
java rsa 기반의 암호화  (0) 2016.01.04
자바 메모리 구조  (0) 2010.08.26