본문 바로가기
백엔드/Java

멀티스레드 환경에서의 Thread-safe 테스트

by david100gom 2024. 3. 20.
[문제코드]
@Service
public class MemberServiceImpl{
  
    @Autowired
    private UserRepository userRepository;
  
    private Member member = new Member();
  
    public void createUser(String id, String name) throws Exception {
  
        member.setID(id);
        member.setName(name);
        userRepository.insertUser(member);
  
    }
}
 
[해결 코드]
@Service
public class MemberServiceImpl{
  
    @Autowired
    private UserRepository userRepository;
    
    public void createUser(String id, String name) throws Exception {
        Member member = new Member();
        member.setID(id);
        member.setName(name);
        userRepository.insertUser(member);
  
    }
}
Singleton 의 경우 멀티스레드 환경에서 static이 아니여도 멤버변수의 값이 공유될수 있다. (스레드에 안전하지 않다.)
 
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;
    }
}
 
public class StaticMethodMultiThreadTest {
    public static void main(String arg[]) {
        int exeCnt = 100;
        for (int i = 0; i < exeCnt; i++) {
            new Thread(new TestThreadClass()).start();
        }
    }
}
 
 
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 {
    private static TestThreadClass2 uniqueInstance;
    private TestThreadClass2() {
    } // <--- 생성자는 private -- 외부에서 new 를 사용하여 객체를 생성할 수 없다...
     
    public static TestThreadClass2 getInstance() { // 객체를 생성하는 static 메소드 하나
 
        if (uniqueInstance == null ) {
            synchronized( TestThreadClass2.class ) {
                if(uniqueInstance == null ) {
                    uniqueInstance = new TestThreadClass2();   
                }
            }
        }
 
        return uniqueInstance;
    }
 
    long threadSafeInt2 = 0;
    Member member = new Member();
 
    /**
    *
    * - 결과 : 로컬 변수는 각 스레드의 stack에 저장하기에 multi thread 환경에서도 safe
    * - 참고 : http://tutorials.jenkov.com/java-concurrency/thread-safety.html
    *
    * @param threadName 스레드 이름
    */
 
    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());
    }
}

'백엔드 > Java' 카테고리의 다른 글

다중 transactionManager  (0) 2024.03.20
Spring AOP  (0) 2024.03.20
Spring @Scheduled 사용시  (0) 2024.03.20
Filter 와 Interceptor  (0) 2024.03.20
하나의 프레임워크에서어 앱 업로드와 웹 업로드시 문제점  (0) 2024.03.20
PK (Auto_increment) 가져오기  (0) 2024.03.20
@Async가 먹히지 않는 경우는 3가지  (0) 2024.03.20
AES-256  (0) 2024.03.20

댓글