들어가기 앞서
과거 면접 때, Synchronized(동기화)에 대한 질문을 받았고, 해당 내용에 대하여 대답하지 못했다. 우연히 개발을 하던 중 접할 수 있어서 간단하게 작성해 보려고 합니다. 실무에서는 대부분 멀티 스레드 환경에서 개발을 하게 되는데 만약 자바 개발자를 목표로 하고 있고, 된다면 멀티 스레드에 동기화와 같은 문제를 마주할 수 있습니다.
필자는 실무에서 해당 키워드를 메일 전송하는 서비스에서 확인할 수 있었다. 실제로 인스타그램, 페이스북 등 좋아요 기능이나, 동기화가 필요한 작업에서 유용하게 사용될 것이다.
멀티 스레딩 이란?
간략하게, 프로그램이나 애플리케이션이 한 번에 2개 이상의 작업을 처리하고 해당 작업을 동기화할 수 있는 기술
(해당 내용의 설명이 부족하여, 상세한 내용은 블로그 글로 따로 정리하도록 하겠습니다.)
Synchronized 란?
멀티 스레딩일 경우, 같은 프로세스 내의 자원을 공유하기 때문에 스레드 간에 서로의 작업에 영향을 줄 수 있습니다. 이를 예방하고 방지하기 위한 방법으로 Synchronized 키워드를 사용할 수 있습니다. 한 스레드가 작업 중인 것을 다른 스레드가 접근 (간섭) 하지 못하도록 막는 것을 스레드 동기화 라고 합니다.
스레드 동기화를 위하여 공용 데이터를 사용하는 코드 영역을 임계 영역으로 지정합니다. 그 후 공유 데이터가 가지고 있는 lock을 획득한 단 하나의 스레드만 코드를 수행할 수 있게 하여 스레드 동기화를 할 수 있다. 물론 메서드 전체를 임계 영역으로 지정할 수 있고, 특정한 영역을 임계 영역으로 지정할 수 있다.
추가적으로 과분별한 동기화 키워드의 사용은 프로그램 성능 저하를 일으킬 수 있습니다. 서버의 부하를 상황에 따라서, 개발자의 판단에 따라서, 사용 빈도 나 영역을 설정해서 사용하면 됩니다.
바로 코드를 보자
CustomerBiz.java
package syncronized;
public class CustomerBiz {
public static void main(String[] args) {
Taskable task = new Taskable();
// 스레드 3개
Thread th0 = new Thread(task);
Thread th1 = new Thread(task);
Thread th2 = new Thread(task);
// 스레드 실행
th0.start();
th1.start();
th2.start();
}
}
AccountBiz.java
package syncronized;
public class AccountBiz {
// 10000 원 출금 한도의 통장
public final int limit = 10000;
// 통장 잔액 50000 원
public int balance = 50000;
public int doWithdraw(int money){
if (money > limit) {
return balance;
}
for (int i = 0; i < 3; i ++) {
try {
// 출금 금액 빼기
balance -= money;
Thread thread = Thread.currentThread();
System.out.println(thread.getName()+ "님께서 출금을 하셨습니다. 잔액은 " + balance + " 입니다.");
Thread.sleep(500);
} catch (Exception e) {
System.out.println(e);
}
}
return balance;
}
}
Taskable.java
package syncronized;
public class Taskable implements Runnable{
AccountBiz accountBiz = new AccountBiz();
@Override
public void run() {
// 1000원 씩 출금
accountBiz.doWithdraw(1000);
}
}
출력 결과
출력된 결과를 보면 알겠지만, 잔액 자체가 제대로 줄지 않는다. 중복이 되기도 하고 잘못 보면 0원을 출력했다고 생각할 것이다. 물론 접근 순서도 일정하지 않다. 만약 실제 은행에서 다음과 같이 통장에 조회가 되었다면, 창구가 마비가 되었을 것이다. 그렇다면 Synchronized 키워드를 사용한 코드를 보자.
AccountBiz.java ( 동기화를 하고자 하는 함수에 synchronized 키워드를 사용) - 이 파일만 수정
package syncronized;
public class AccountBiz {
// 10000 원 출금 한도의 통장
public final int limit = 10000;
// 통장 잔액 50000 원
public int balance = 50000;
// 동기화를 사용하고자 하는 함수에 synchronized 키워드를 사용한다
public synchronized int doWithdraw(int money){
if (money > limit) {
return balance;
}
for (int i = 0; i < 3; i ++) {
try {
// 출금 금액 빼기
balance -= money;
Thread thread = Thread.currentThread();
System.out.println(thread.getName()+ "님께서 출금을 하셨습니다. 잔액은 " + balance + " 입니다.");
Thread.sleep(500);
} catch (Exception e) {
System.out.println(e);
}
}
return balance;
}
}
출력 결과
정상적으로 나오는 것을 확인할 수 있다.
위에서 한 번 말씀드린 것처럼, 필자는 메일이 송신되는 서비스에 동기화 키워드를 확인할 수 있었다. 개발을 하면서, 동기화가 필요한 상황에는 synchronized라는 키워드를 사용해서 다음과 같이 할 수 있다는 것을 공유하고자 블로그 글을 작성합니다. 조금이라도 도움이 되셨으면 좋겠습니다.
아래 블로그에서 코드를 참고하였습니다.
'개발 > JAVA' 카테고리의 다른 글
[JAVA] JAVA8 과 JAVA11 의 차이점을 알아보자. (0) | 2023.09.23 |
---|---|
[JAVA] 함수형 프로그래밍 (0) | 2023.09.22 |
[JAVA] 접근 제어자 (Access Modifier) 에 대하여 (0) | 2023.09.16 |
[JAVA] JAVA7 과 JAVA8 의 차이점을 알아보자. (0) | 2023.09.08 |
[JAVA] 예외(Exception) 처리에 대해서 알아보자. (0) | 2023.08.26 |