-
Java | Thread (3) Synchronization 동기화JAVA/JAVA 2020. 2. 11. 17:06
Synchronization 동기화
하나의 자원을 여러 태스크가 사용하려고할 때
한 시점에서 하나의 태스크만 사용할 수 있도록 하는 것- 쉽게 얘기하면 A, B 스레드가 한 공간에서 동시에 작업을 하려고할 때
A 스레드의 작업이 끝날 때까지 B가 기다려주는 것(반대의 경우도 마찬가지) - 대부분의 응용 프로그램에서 다수의 스레드가 공유할 수 있는 영역이 요구됨
- 공유하는 부분은 상호 배타적으로 사용되어야 함
- ex) 좌석 예매 시스템
판매처가 2곳 이상일 때 동기화가 되지 않는다면
같은 좌석을 여러 명의 사람에게 판매하는 경우가 생김 - DB연동시 많이 사용(조회, 수정, 삭제)
트랜잭션과 연관이 있음(commit, rollback)
Critical Section 임계 영역
- 상호배타적으로 사용되는 공유 영역
- 자바는 한 순간에 하나의 스레드만 실행하도록 하는 synchronized method 제공
- 한 스레드가 synchronized method를 수행 중이면 다른 스레드는 대기함
synchronized 예약어
메소드에 Lock을 걸어서 동기화를 도와주는 예약어
형식 ①
메소드 자체에 Lock을 거는 경우
접근 제어자 synchronized 반환형 메소드명(){}
※ 해당 메소드를 A스레드에서 실행중이면 B스레드는 A의 작업이 끝날때 까지 대기
예제
입출력(RandomAccessFile)과 Thread의 동기화를 활용한 예제
RandomAccessFile: 특정위치에 접근해서 파일을 읽거나 쓰는 입출력 클래스package j200211; import java.io.*; import java.lang.Thread; public class ShareTest implements Runnable { // RandomAccessFile 클래스형 변수 선언 RandomAccessFile raf = null; public ShareTest() { try { // 파일 생성, 읽기/쓰기가 가능하도록 rw 모드로 설정 raf = new RandomAccessFile("result.txt", "rw"); // Thread 객체 생성, this는 Runnable 구현 클래스인 ShareTest 클래스를 지칭 Thread t1 = new Thread(this, "MJH"); Thread t2 = new Thread(this, "TEST"); // Thread 객체 실행 t1.start(); t2.start(); } catch (Exception e) { System.out.println(e); } } // 동기화 → synchronized 예약어로 run() 메소드에 lock 걸기 public synchronized void run() { // writeBytes(), raf에 글자쓰기 try { for (int i = 0; i < 1000; i++) { // Thread 명 + File Pointer 위치 + 줄바꿈(\r\n: 윈도우 운영체제 줄바꿈) raf.writeBytes(Thread.currentThread().getName() + "[" + i + "]" + raf.getFilePointer() + "\r\n"); } } catch (Exception e) { System.out.println(e); } } public static void main(String[] args) { // ShareTest 객체 생성 new ShareTest(); /* MJH[0]0 MJH[1]9 MJH[2]18 .... */ } }
※ MJH 스레드가 작업을 전부 마친 뒤에 TEST 스레드가 작업을 시작함
형식 ②
메소드 내부의 특정 부분에만 Lock을 거는 경우
synchronized(공유 데이터){ // Java Code; }
※ DB연동시 많이 사용하는 형식
예제
급여계좌(공유 데이터)에서 ATM이 보험금과 공과금을 일정 금액씩 인출하는 프로그램 작성
package j200211; class ATM implements Runnable { // 급여계좌 잔액 private long money = 10000; public void run() { // 동기화 → ATM 객체에 복수의 스레드가 접근할 때 서로 기다리도록 함 synchronized (this) { for (int i = 0; i < 5; i++) { try { // 스레드가 1초간 대기하도록 함 Thread.sleep(1000); } catch (Exception e) { System.out.println(e); } // 잔액이 0보다 작아지면 반복문에서 탈출 if (check() <= 0) break; // 출금 withdraw(1000); } } } // 인출 메소드 public void withdraw(long money) { // check() - money > 0 인 경우에 출금 if (check() > money) { this.money -= money; // 현재 Thread 및 잔액 출력 System.out.println(Thread.currentThread().getName() + ", " + check()); } else { System.out.println("잔액이 부족합니다!"); } } // 잔액 조회 public long check() { return money; } } public class SyncTest { public static void main(String[] args) { // 객체를 하나만 생성해야 여러 스레드에서 하나의 데이터를 공유할 수 있음 ATM atm = new ATM(); // Thread 생성 및 실행 Thread atm1 = new Thread(atm, "보헙금"); Thread atm2 = new Thread(atm, "공과금"); atm1.start(); atm2.start(); /* 보헙금, 9000 보헙금, 8000 보헙금, 7000 보헙금, 6000 보헙금, 5000 공과금, 4000 공과금, 3000 공과금, 2000 공과금, 1000 잔액이 부족합니다! */ } }
두 개 이상의 스레드를 사용할 때 하나의 공유 데이터에 대하여
각 스레드가 배타적으로 작업을 수행하도록 하는 동기화에 대해 살펴보았습니다.우선순위를 부여하는 것보다도 확실하게 스레드의 작업을 분리할 수 있으며
DB와 연동하거나 작업이 동시에 이루어지면 안 되는 메소드가 있는 경우에
Synchronized 예약어를 사용할 수 있겠습니다.'JAVA > JAVA' 카테고리의 다른 글
Java | Singleton Pattern 싱글톤 패턴 (0) 2020.02.11 Java | I/O RandomAccessFile (0) 2020.02.11 Java | Thread (2) Thread 생성 & Multi Thread (0) 2020.02.10 Java | Thread (1) 개요 (0) 2020.02.10 Java | Generic (2) <?> & <T extends Class> & <? super Class> (0) 2020.02.10 - 쉽게 얘기하면 A, B 스레드가 한 공간에서 동시에 작업을 하려고할 때