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

1. Thread


프로세스의 자원을 이용해서 실제로 수행하는 것이 Thread 이다.
- 개별적인 메모리공간(호출스택)을 필요로 한다.
- main Thread : main method의 작업을 수행하는것도 Thread이다.
- 실행중인 사용자 Thread 가 하나도 없을 때 프로그램은 종료한다.
  (=> main Thread가 끝나도 끝나지 않은 Thread가 있다면 프로그램은 종료되지 않음)

2. run() & start()


▶run()  
- Thread를 통해 작업하고자 하는 내용으로 run()의 { } 안을 채운다.
- main method에서 run을 호출하는 것은 생성된 Thread를 실행시키는 것이 아니라 
  단순히 class에 선언된 method를 호출하는 것.
▶start()
- 새로운 Thread가 작업을 실행하는데 필요한 호출스택(call stack)을 생성한 다음 run() 호출 
  →생성된 호출스택에 run()이 첫번째로 올라가게 한다.

3. Thread의 life Cycle

 

-쓰레드가 생성되면 아래 그림이 보여주는 네가지 상태 중 한가지 상태에 있게 된다.

 

 

3-1.
new 상태 : Thread class가 키워드 new를 통해서 인스턴스화 된 상태
runnable 상태 : start method 호출 후. 모든 실행의 준비를 마치고 스케쥴러에 의해 실행의 대상으로 선택되기를 기다리는 상태
blocked 상태 : 실행중인 Thread가 sleep 이나 join 메소드를 호출하는 등의 상황에서 cpu를 다른 thread에게 양보하고,
                        그 thread는 blocked상태가 된다.
dead 상태 : run 메소드의 실행이 완료되어서 run 메소드를 빠져나오게 되면 해당 thread는 dead 상태가 된다.
                   thread의 실행을 위해 할당받았던 메모리 등 모든 정보가 소멸.


4. Thread를 구현하는 방법

4-1. Thread class를 상속받는 방법


-Thread를 상속받은 클래스의 인스턴스를 생성한다.

 

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
 
//Single Thread
public class SingleThreadEx extends Thread{
   public int[] temp;
   public SingleThreadEx(String threadname){        //생성자 함수 (main에서 SingleThreadEx의 "첫번째"를 받음)
      super(threadname);    //참조변수
      temp = new int[10];    //배열 생성
      for(int start = 0; start < temp.length; start++){        
         temp[start] = start;    //배열 temp[start]에 값이 들어감.
      }
   }
   
   public void run(){    //Thread class의 run()을 오버라이딩
      for(int start : temp){
         try
            sleep(1000);        //1초 지연
         }catch (InterruptedException ie){    // 예외처리
            ie.printStackTrace();    //오류가 뭔지 찍어주는 함수
         }
         System.out.printf("스레드 이름 : %s ,",currentThread().getName());    //현재 thread의 이름(첫번째) 출력
         System.out.printf("temp value : %d %n", start);        //start의 값 찍어줌.
      }
   }
   public static void main(String[] args){
      SingleThreadEx st = new SingleThreadEx("첫번째");    //생성자가 불러진다.
      st.start();    // runnable 대기상태로 가서 스케쥴러가 run을 
   }
   
   
}
cs

 

4-2. Runnable interface를 구현하는 방법


-Runnable을 구현한 class의 인스턴스를 생성
-Runnable interface를 구현한 class의 instance를 생성한 다음, 이 instance를 Thread class의 생성자의 매개변수로 제공

 

 

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
public class Thread1 implements Runnable{
   private int[] temp;
   public Thread1(){
       temp=new int[10];
      for(int start=0; start<temp.length; start++){
         Thread.currentThread().setName("첫번째");
         temp[start]=start;
      }
   }
   public void run(){
      for(int start:temp){
         try{
            Thread.sleep(1000);
         }
         catch(InterruptedException ie){
            ie.printStackTrace();
            
         }
         System.out.printf("스레드 이름:%s", Thread.currentThread().getName());
         System.out.printf("temp value:%d %n",start);
      }
   }
    public static void main(String[]ar){
       Thread1 st= new Thread1();
       Thread ct = new Thread(st,"첫번째");
       ct.start();
    }
}
cs

 

 

(코드 둘 다 출력값은 똑같다)

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

[Java] Thread_2  (0) 2017.09.04

+ Recent posts