이전 글에 이어서 계속해서 Thread 동시성 문제를 보겠습니다.
이번에는 동시성 해결방법을 다루어보겠습니다.
https://getthismoment.tistory.com/155
Thread 동시성 문제 해결 방법으로 우선 ThreadLocal 을 살펴보겠습니다.
ThreadLocal
ThreadLocal 사용방법은 주입해서 사용할 서비스 로직에 구현하면 됩니다.
ThreadLocal은 여러 스레드가 실행되어도 각 스레드에서 독립된 실행을 보장하는 방법입니다.
public class BankBook {
private int balance = 500; // 남은 금액
private ThreadLocal<Integer> threadLocal = new ThreadLocal();
// 입금
public void deposit() {
String name = Thread.currentThread().getName();
threadLocal.set(balance);
while(true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
threadLocal.set(threadLocal.get() + 400);
System.out.println(name + " [입금] 남은 금액: " + threadLocal.get());
}
}
// 출금
public void withdraw() {
String name = Thread.currentThread().getName();
threadLocal.set(balance);
while(true) {
int randomMoney = (int) Math.ceil(Math.random() * 10)*100; // 100~1000 자연수
if(threadLocal.get() >= randomMoney) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
balance = threadLocal.get() - randomMoney;
threadLocal.set(balance);
System.out.println(name + " [출금] 남은 금액: " + threadLocal.get());
}
}
}
}
Service 에 해당하는 BankBook 로직을 다음과 같이 수정했습니다.
동시성 문제가 발생하는 예전 코드는
https://getthismoment.tistory.com/155
이전 포스트에서 비교해서 보면 좋을 것 같습니다.
public class BankBookTest {
private BankBook bankBook = new BankBook();
@Test
public void test() throws InterruptedException {
Thread depositThread1 = new Thread(new DepositThread(bankBook));
depositThread1.setName("deposit Thread1");
Thread depositThread2 = new Thread(new DepositThread(bankBook));
depositThread2.setName("deposit Thread2");
Thread withdrawThread1 = new Thread(new WithdrawThread(bankBook));
withdrawThread1.setName("withdraw Thread1");
Thread withdrawThread2 = new Thread(new WithdrawThread(bankBook));
withdrawThread2.setName("withdraw Thread2");
depositThread1.start();
depositThread2.start();
withdrawThread1.start();
Thread.sleep(100);
withdrawThread2.start();
Thread.sleep(2000);
}
}
DepositThread 와 WithdrawThread 클래스는 이전 로직과 같아서 생략합니다.
결과값 비교를 위해 depositThread2 인스턴스를 추가로 생성했습니다.
그럼 입금이 스레드가 총 2개가 존재하게 됩니다.
실행결과를 확인해보면 다음과 같습니다.
결과를 보시면 남음 금액이 마이너스가 등장하지는 않습니다.
하지만 실행 결과가 의도한 결과가 아닙니다.
실행 결과를 보면 각 스레드는 자기 스레드의 남은 금액(balance)만 수정합니다.
ThreadLocal 은 스레드간에 독립성은 보장하지만, 스레드 간의 값을 공유해야할 경우에는 부적합 합니다.
즉, 남은 금액인 balance 프로퍼티의 값을 스레드 간에 공유해야합니다.
물론 ThreadLocal를 사용해도 balance 프로퍼티를 공유할 수는 있지만 그렇게 된다면 스레드 간의 독립성이 보장되지 않습니다.
그럼 언제 ThrealLocal 사용해야 할까요?
스레드 간의 값을 실시간으로 공유하지 않고 독립적으로만 사용해야하는 경우.
또는 스레드 객체에서 사용할 값을 외부에서 파라미터 형식으로 받아 스레드마다 독립적으로 사용하는 경우.
이러한 경우에 ThrealLocal을 사용하면 될 것 같습니다.
ThrealLocal로 손쉽게 동시성 문제를 해결할 수 있지만 용도에 맞게 사용해야하는 것이죠.
이번 포스트 ThrealLocal를 소개하고 어떤 경우에 동시성 문제를 해결하는 수단으로 써야하는 살펴봤습니다.
다음 포스트에서는 Synchronzied 를 통해서 Thread 동시성 문제를 해결해보겠습니다.
'Java' 카테고리의 다른 글
Java - 람다 스트림 예제 (0) | 2023.02.10 |
---|---|
Java - Thread 동시성 문제3 (Synchroized) (0) | 2022.05.04 |
Java - Thread 동시성 문제1 (0) | 2022.05.04 |
Jave - Thread 개괄 (0) | 2022.05.03 |
Java - 객체 지향 설계 원칙 SOLID (0) | 2022.04.09 |
댓글