싱글톤 인스턴스에 여러 쓰레드가 접근한다면 지연이 발생할까?
라는 질문을 가지고 테스트했습니다.🛠️ 실습환경
Lang: Java 17
Test: jUnit5📝 실습 목표
멀티쓰레드 환경에서 싱글톤 인스턴스에 여러 쓰레드가 접근한다면 지연이 발생할까? 에 대한 답변
128
, 256
, 512
회로 고정합니다import com.github.f4b6a3.tsid.TsidFactory;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Stream;
public class TsidDurationTest {
static String pathFormat = "src/test/resources/results%s-ready%s.csv";
static void write(int numberOfRequest, int numberOfInstance, long s, long m, long n) {
String path = String.format(pathFormat, numberOfRequest, numberOfInstance);
try (BufferedWriter writer = new BufferedWriter(new FileWriter(path, true))) {
writer.append(String.format("%s,%s,%s\n", s, m, n));
} catch (IOException e) {
e.printStackTrace();
}
}
static Stream<Arguments> args() {
List<Integer> numberOfRequests = List.of(128, 256, 512);
List<Arguments> args = new ArrayList<>();
numberOfRequests.forEach(value1 -> {
args.add(Arguments.of(value1, 10));
args.add(Arguments.of(value1, 100));
});
return args.stream();
}
@ParameterizedTest
@MethodSource("args")
void singleInstanceVsMultiInstance(int numberOfRequests, int numberOfInstance) throws InterruptedException {
ExecutorService service = Executors.newCachedThreadPool();
List<Callable<Long>> singleTasks = new ArrayList<>();
TsidFactory singleFactory = TsidFactory.builder().withNode(0).withNodeBits(16).build();
while (singleTasks.size() < numberOfRequests) {
singleTasks.add(() -> singleFactory.create().toLong());
}
long singleStart = System.nanoTime();
service.invokeAll(singleTasks);
long singleDuration = System.nanoTime() - singleStart;
List<TsidFactory> factories = new ArrayList<>();
while (factories.size() < numberOfInstance) {
factories.add(TsidFactory.builder().withNode(0).withNodeBits(16).build());
}
List<Callable<Long>> multiTasks = new ArrayList<>();
while (multiTasks.size() < numberOfRequests) {
for (TsidFactory factory : factories) {
multiTasks.add(() -> factory.create().toLong());
}
}
long multiStart = System.nanoTime();
service.invokeAll(multiTasks);
long multiDuration = System.nanoTime() - multiStart;
List<Callable<Long>> newTasks = new ArrayList<>();
while (newTasks.size() < numberOfRequests) {
newTasks.add(() -> TsidFactory.builder().withNode(0).withNodeBits(16).build().create().toLong());
}
long newStart = System.nanoTime();
service.invokeAll(newTasks);
long newDuration = System.nanoTime() - newStart;
write(numberOfRequests, numberOfInstance, singleDuration, multiDuration, newDuration);
}
}
공유 스프레드시트 링크
결과 차트를 만들어 표와 그래프를 나타낸 문서입니다.
FOO
, BAR
테이블이 있다고 가정할 때 둘의 식별자 값이 중복돼도 괜찮은 경우 인스턴스를 나누어 사용할 수 있습니다.synchronized
, ReentrantLock
처럼 동기화 작업을 수행하는 경우 사용할 수 있습니다.동시성 처리가 필요한 객체를 싱글톤 객체와 미리 생성된 객체, 그리고 매번 새 객체를 생성해 사용하고 여러 작업이 집중될 때 작업 수행 소요시간을 비교해봤습니다.
테스트코드, 과정에서 이상한점, 문제점 등 이슈가 발견되면 댓글이나 이메일로 알려주세요. :)