1. 스레드 동기화 (Thread Synchronization)
critical section 에 두 개 이상의 thread 가 동시 접근 하는 경우 발생하는 문제를 해결하기 위한 기법으로 하나의 스레드가 공유자원에 접근하면 해당 객체를 Lock 하여 다른 스레드의 접근을 제어함
2. Java 동기화 구현 방법
3. sysnchronized 메서드
4. sysnchronized 블럭
synchronized(객체) {
수행문;
}
5. 스레드 동기화가 필요한 상황
6. 스레드 동기화 적용
class Bank{
private int money = 10000;
public synchronized void saveMoney(int save){ # synchronized 키워드 적용
# 특정 스레드가 해당 메서드를 수행할 동안 Bank 객체 접근 불가
int m = this.getMoney();
try {
Thread.sleep(3000); # 출력 결과를 좀 더 이해하기 쉽게 3초 정도 딜레이
} catch (InterruptedException e) {
e.printStackTrace();
}
setMoney( m + save);
}
public synchronized void minusMoney(int minus){ # synchronized 키워드 적용
# 특정 스레드가 해당 메서드를 수행할 동안 Bank 객체 접근 불가
int m = this.getMoney();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
setMoney( m - minus);
}
public int getMoney(){
return money;
}
public void saveMoney(int save){
syschronized(this){ # 특정 스레드가 해당 블럭을 수행할 동안 this(Bank) 객체 접근 불가
int m = this.getMoney();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
setMoney( m + save);
}
class Park extends Thread{
public void run(){
System.out.println("start save");
SyncMain.myBank.saveMoney(3000); # 정적 인스턴스의 메서드 접근
System.out.println("saveMoney(3000): " + SyncMain.myBank.getMoney() );
}
}
class Parkson extends Thread{
public void run(){
System.out.println("start minus");
SyncMain.myBank.minusMoney(1000); # 정적 인스턴스의 메서드 접근
System.out.println("minusMoney(1000): " + SyncMain.myBank.getMoney() );
}
}
public class SyncMain {
public static Bank myBank = new Bank(); # 정적 인스턴스 생성
public static void main(String[] args) throws InterruptedException {
Park p = new Park();
p.start();
Thread.sleep(200);
Parkson pson = new ParkWife();
pw.start();
}
}
1. wait() / notify() 메서드
2. 도서관 대여 및 반납 프로그램
class Library{
public ArrayList<String> shelf = new ArrayList<String>();
public Library(){ # 3개의 책이 존재
shelf.add("태백산맥 1");
shelf.add("태백산맥 2");
shelf.add("태백산맥 3");
}
public synchronized String lendBook() throws InterruptedException{
Thread t = Thread.currentThread();
if(shelf.size() == 0 ) { # 책이 없다면
System.out.println(t.getName() + " waiting start");
wait(); # wait 상태로 빠짐
System.out.println(t.getName() + " waiting end");
}
String book = shelf.remove(0);
System.out.println(t.getName() + ": " + book + " lend");
return book;
}
public synchronized void returnBook(String book){
Thread t = Thread.currentThread();
shelf.add(book); # 책을 반납하면
notify(); # 대기하고 있는 스레드 중 하나를 랜덤으로 runnable 상태로 만듬
System.out.println(t.getName() + ": " + book + " return");
}
}
class Student extends Thread{
Student(String name){
super(name);
}
public void run(){
try{
String title = LibraryMain.library.lendBook(); # 책을 빌리려고 하는데
if( title == null ) return; # 해당 책이 없다면 없다면 그냥 return
sleep(5000); # 책이 있다면 빌리고 5초 동안 읽음
LibraryMain.library.returnBook(title); # 반납
}catch (InterruptedException e) {
System.out.println(e);
}
}
}
public class LibraryMain {
public static Library library = new Library(); # 정적 멤버변수로 Library 인스턴스 생성
public static void main(String[] args) {
Student std1 = new Student("학생1");
Student std2 = new Student("학생2");
Student std3 = new Student("학생3");
Student std4 = new Student("학생4");
Student std5 = new Student("학생5");
Student std6 = new Student("학생6");
std1.start();
std2.start();
std3.start();
std4.start();
std5.start();
std6.start();
}
}
public synchronized String lendBook() throws InterruptedException{
Thread t = Thread.currentThread();
while( shelf.size() == 0 ){
System.out.println(t.getName() + " waiting start");
wait();
System.out.println(t.getName() + " waiting end");
}
String book = shelf.remove(0);
System.out.println(t.getName() + ": " + book + " lend");
return book;
}
public synchronized void returnBook(String book){
Thread t = Thread.currentThread();
shelf.add(book);
notifyAll();
System.out.println(t.getName() + ": " + book + " return");
}