Avoid thread pinning in SseEmitter write operations

This commit changes the `synchronized` usage into a `ReentrantLock`, in
order to guard write operations with a construct that does not pin
virtual threads to the current platform thread on JDK21.

Closes gh-30996
This commit is contained in:
Brian Clozel 2023-08-04 14:57:36 +02:00
parent 9908967954
commit 646fd3edcc
1 changed files with 13 additions and 1 deletions

View File

@ -21,6 +21,8 @@ import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
@ -36,12 +38,18 @@ import org.springframework.util.StringUtils;
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @author Sam Brannen
* @author Brian Clozel
* @since 4.2
*/
public class SseEmitter extends ResponseBodyEmitter {
private static final MediaType TEXT_PLAIN = new MediaType("text", "plain", StandardCharsets.UTF_8);
/**
* Guards access to write operations on the response.
*/
private final Lock writeLock = new ReentrantLock();
/**
* Create a new SseEmitter instance.
*/
@ -122,9 +130,13 @@ public class SseEmitter extends ResponseBodyEmitter {
*/
public void send(SseEventBuilder builder) throws IOException {
Set<DataWithMediaType> dataToSend = builder.build();
synchronized (this) {
this.writeLock.lock();
try {
super.send(dataToSend);
}
finally {
this.writeLock.unlock();
}
}
@Override