Thread-safe하기 위한 동기화 리마인드를 위한 소스.
ThreadSyncronizedTest.java
package com.practice;
public class ThreadSyncronizedTest {
public static void main(String[] args) {
Account humingAccount = new Account();
humingAccount.setUserFullName("Huming");
humingAccount.setUserNumber(0);
humingAccount.setUserBalance(8000);
System.out.println("Account Name is " + humingAccount.getUserFullName());
System.out.println("Huming's initial balance : " + humingAccount.getUserBalance());
//Run
userTaskRunnable userTaskRunnable = new userTaskRunnable(humingAccount);
Thread t1 = new Thread(userTaskRunnable);
Thread t2 = new Thread(userTaskRunnable);
t1.setName("t1_Thread");
t2.setName("t2_Thread");
t1.start();
t2.start();
}
}
class Account {
int userNumber;
String userFullName;
double userBalance;
public void setUserNumber(int userNumber) {
this.userNumber = userNumber;
}
public void setUserFullName(String userFullName) {
this.userFullName = userFullName;
}
public void setUserBalance(double userBalance) {
this.userBalance = userBalance;
}
public int getUserNumber() {
return userNumber;
}
public String getUserFullName() {
return userFullName;
}
public double getUserBalance() {
return userBalance;
}
public boolean deposit(double amount ) {
double newBalance;
synchronized (this) {
if (amount < 0.0) {
return false;
} else {
newBalance = userBalance + amount;
userBalance = newBalance;
return true;
}
}
}
public boolean withdraw( double amount ) {
double newBalance;
// syncronized 를 사용하여 쓰레드 safe 하게 작성
synchronized (this) {
if (amount > userBalance) {
return false;
} else {
try {
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + ">> Witdraw Amount : " + amount);
//Thread.sleep(1000);
newBalance = userBalance - amount;
userBalance = newBalance;
System.out.println(thread.getName() + ">> Balance : " + userBalance);
return true;
} catch (Exception e) {
return false;
}
}
}
}
}
userTaskRunnable.java
package com.practice;
public class userTaskRunnable implements Runnable {
Account userAccount;
public userTaskRunnable(Account _userAccount) {
this.userAccount = _userAccount;
}
public void run() {
while(userAccount.userBalance > 0) {
double money = 100.0;
userAccount.withdraw(money);
}
}
}
- main 함수에서 쓰레드를 작동시키면, runnable을 통해 쓰레드별로 withdraw(money) 호출
- synchronized 미사용의 경우,
- newBalance = userBalance – amount; 까지 처리 후.. userBalance가 처리되지 않은 상태에서 타쓰레드로 컨텍스트 스위칭이 발생한다고 가정하자.
- t1 에서 100달러 차감 후, userBalance가 갱신되지 않은 상태에서 t2의 100달러가 차감되므로 잔고는 여전히 900원. (t1과 t2가 100달러씩 200달러를 차감했지만, 잔고는 갱신되지 않았다)
- syncronized를 사용하여 쓰레드 동기화 (타쓰레드 블록킹)을 시행함으로써 클래스 데이터의 변경을 방지할 수 있다.