멀티스레드 환경에서의 Thread-safe 테스트
스프링 프레임워크의 기본 bean scope 는 singleton 이며, 멀티스레드 환경에서 클래스내의 멤버변수로 인한 데이터가 꼬이는 문제가 발생한다. 가능하면 멤버변수는 DI 를 하는 bean 외에는 사용하지 않는것이 정신 건강에 좋다. 또한, bean scope 를 prototype 으로 구성하면 생명주기를 스프링 프레임워크가 관리하지 않기 때문에 객체 사용이 끝나면 직접 소멸시켜줘야 한다. 그러지 않으면 스레드 락이 생겨 애플리케이션 성능에 심각한 문제가 발생한다.
아래 4개 클래스를 생성후, StaticMethodMultiThreadTest 를 실행하여 멤버변수의 위치에 따른 결과값을 테스트한다.
public class Member {
String id;
String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class TestThreadClass extends Thread {
static int i = 1;
public void run() {
if(i%2 == 0) {
TestThreadClass2 t2 = TestThreadClass2.getInstance();
t2.testStaticMethod(this.getName());
}else{
TestThreadClass2 t2 = TestThreadClass2.getInstance();
t2.testStaticMethod2(this.getName());
}
i++;
}
}
public class TestThreadClass2 {
long threadSafeInt2 = 0;
Member member = new Member();
private static TestThreadClass2 uniqueInstance;
private TestThreadClass2() {
}
// singleton
public static TestThreadClass2 getInstance() {
if (uniqueInstance == null ) {
synchronized( TestThreadClass2.class ) {
if(uniqueInstance == null ) {
uniqueInstance = new TestThreadClass2();
}
}
}
return uniqueInstance;
}
public void testStaticMethod(String threadName) {
System.out.println("threadSafeInt Start : " + threadName);
long threadSafeInt = 0;
threadSafeInt++; // 항상 1 : 로컬 변수의 값은 multiple thread에 safe
System.out.println("threadSafeInt : " + threadSafeInt);
if(threadSafeInt != 1) {
System.out.println("threadSafeInt It is not thread safe : " + threadSafeInt);
}
System.out.println("threadSafeInt End : " + threadName);
}
public void testStaticMethod2(String threadName) {
member.setId("ID : "+String.valueOf(threadSafeInt2));
member.setName("이름 : "+String.valueOf(threadSafeInt2));
System.out.println("testStaticMethod2 Start : " + threadName);
threadSafeInt2++; // 계속 증가 : not thread safe
System.out.println("testStaticMethod2 threadSafeInt : " + threadSafeInt2);
if (threadSafeInt2 != 1) {
System.out.println("testStaticMethod2 It is not thread safe : " + threadSafeInt2);
}
System.out.println("testStaticMethod2 End : " + threadName);
// 결과 : ID 와 Name 이 같은 값으로 나올것 같지만, 실제로는 데이터가 섞임. not thread safe
System.out.println("testStaticMethod2 Member id : " + member.getId()+ " name : "+member.getName());
}
}
public class StaticMethodMultiThreadTest {
public static void main(String arg[]) {
int exeCnt = 100;
for (int i = 0; i < exeCnt; i++) {
new Thread(new TestThreadClass()).start();
}
}
}
'백엔드 > Java' 카테고리의 다른 글
자바 멤버변수 (0) | 2020.07.12 |
---|---|
클래스 다이어그램 (0) | 2020.07.11 |
OAuth2 승인 방식의 종류 (0) | 2020.05.23 |
추상 클래스와 인터페이스의 차이점 (0) | 2020.05.05 |
Jedis Pool 최적화 - JedisPool - redis connection pool (레디스 커넥션 풀) (0) | 2020.02.02 |
StringBuffer vs StringBuilder (0) | 2020.01.27 |
int vs Integer (0) | 2020.01.27 |
리팩토링 맛보기 2탄 (0) | 2020.01.26 |
댓글