1. 동기화


- thread가 진행 중인 작업을 다른 thread가 간섭하지 못하도록 막는 것을 'thread의 동기화(synchronization)이라고 한다.



1-1. method 전체를 임계 영역으로 지정하는 방법


- synchronized method가 호출된 시점부터 해당 메서드가 포함된 객체의 lock을 얻어 작업을 수행하다가 method가 종료되면 lock을 반환한다.
 
1-2. 특정한 영역을 영역으로 지정하는 방법


- method 내의 코드 일부를 { }로 감싸고 중괄호 앞에 synchronize(참조변수)를 붙힌다.  
  이 때 참조변수는 lock을 걸고자 하는 객체를 참조하는 것.
     
 2. wait() & notify()


 - 동기화된 임계 영역의 코드를 수행하다가 작업을 더이상 진행할 상황이 아니면 
   일단 wait()을 호출하여 threadlock을 반납하고 기다리게 한다
   그러면 다른 threadlock을 얻어 해당 객체에 대한 작업을 수행할 수 있게 된다.
   나중에 작업을 진행할 수 있는 상황이 되면 notify()를 호출해서
   작업을 중단했던 thread가 다시 lock을 얻어 작업을 진행할 수 있게 한다.
- waitnotiry(notifyAll) method는 동기화 처리를 해서, 한순간에 하나의 thread만 호출이 가능하도록 한다.(동시호출 아님)


   
3. Multi thread 사용하여 ATM기에서 번갈아가며 돈을 빼는 프로그램을 만들어보장.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class ATM implements Runnable {        //완전추상객체 interface를 받는거/ runnable은 thread를 돌릴 수 있는 환경 제공
private long depositeMoney = 10000;
    public void run() {
        synchronized (this) {    //자기 자신의 class 내에서 동기화 하겠다.
            for (int i = 0; i < 10; i++) {
                notify();    //notify() : thread의 제어권을 넘겨준당. // 처음에는 withdraw 한번 돌고 제어권 넘기고 wait.
                try {
                    wait();
                    Thread.sleep(1000);    //1초 지연
                } catch (InterruptedException e) {    //예외처리
                    e.printStackTrace();
                }
                if (getDepositeMoney() <= 0)
                    break;
                withDraw(1000);    // withDraw 함수 호출
            }
        }
    }
    public void withDraw(long howMuch) {        
        ATM atm  = new ATM();    //객체 생성
 
        if (getDepositeMoney() > 0) {    //돈 1000원씩 까임
            depositeMoney -= howMuch;
            System.out.print(Thread.currentThread().getName()+ " , ");
            System.out.printf("잔액 : %,d 원 %n",getDepositeMoney());
        } else {        // 1000원 이하로 있을 때
            System.out.print(Thread.currentThread().getName()+ " , ");
            System.out.println("잔액이 부족합니다.");
        }
    }
    public long getDepositeMoney() {    //get
        return depositeMoney;
    }
}
 
public class SynchronizedEx {
    public static void main(String[] args) {
        ATM atm = new ATM();
        Thread mother = new Thread(atm, "mother");    //엄마 thread 생성, atm에서 thread를 만들어서 돌려라
        Thread son = new Thread(atm, "son");        
        mother.start();
        son.start();    //thread가 엄마꺼 아들꺼 두개 돌아감.
    }
}
cs




- main에서 mother thread가 먼저 호출될지 son thread가 먼저 호출 될지는 알 수 없다
- 7번 줄에서 notify() 가 호출됐을 때, 먼저 호출된 함수의 제어권이 다음 함수로 넘어가며,
  먼저 호출된 함수는 wait()함수에 의해 잠시 block 상태가 된다.
  for문이 끝날 때 까지 계속 반복하여 중복없이 번갈아 가며 1000원씩 빠져나갈 수 있게 된다.

 

 

 

-결과화면

 

 

4. join()


- 해당 작업의 수행이 끝날 때까지 기다렸다가, 수행이 끝나면 그 결과를 반환한다. 비동기 method이다.
- 비동기 method : 일반적인 method와 달리 method를 호출만 할 뿐, 그 결과를 기다리지 않는다
  내부적으로는 다른 thread에게 작업을 수행하도록 지시만 하고 결과를 기다리지 않고 돌아오는 것.

5. 간단한 예제 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class MyRunnableTwo implements Runnable{
    public void run(){
        System.out.println("run");//2
        first();    
    }
    
    public void first(){
        System.out.println("first");//3
        second();
    }
    
    public void second() {
        System.out.println("second");//4
    }
}
public class JoinEx {
    public static void main(String []args){
        System.out.println(Thread.currentThread().getName()+" start");//1
        Runnable r = new MyRunnableTwo();    //Runnable r class 생성 후 호출
        Thread myThread = new Thread(r);    //r Thread를 실행시킨다.
        myThread.start();    //시작
        try{
            myThread.join();    //모든 Thread가 돌 동안 main이 끝나지 않음 
        }catch(InterruptedException ie){
            ie.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+" end");    //5
    }
}

// 주석에 써진 숫자 순서대로 출력된다. 

cs

 

 

 


 

'Java > Java' 카테고리의 다른 글

[Java] thread_1  (0) 2017.09.04

+ Recent posts