본문 바로가기

JAVA

[WEB]DAY22_쓰레드(Thread), 교착상태(DeadLock), 동기화(Synchronuzed)

쓰레드(Tread)

     프로그램

     프로세스
      - 실행된 프로그램
      - 운영체제로부터 시스템 자원을 할당받는 작업의 단위.
      - JAVA프로그램은 운영체제 대신 JVM에 의해 실행된다.
      - 모든 쓰레드가 종료되어야 프로세스도 종료된다.

          System.exit(0);으로 강제종료하면 모두 종료된다.

     쓰레드
      - 프로세스의 특정한 수행 경로
      - 프로그램 처리 경로.
      - 직렬적이다.
      - JVM에 의해 스케줄링 된다. (각 쓰레드의 순서를 지정하는 기능?) 

     멀티 쓰레드
      - 하나의 프로세스를 동시에 처리하는 것처럼
          보이지만 사실은 매우 짧은 단위로 분할해서
          차례로 처리한다(병렬적).
      - 여러개의 경로를 가질 수 있게 하고
          한 개의 처리경로를 여러개로 나누어
          동시 작업이 가능하다.

      - 장점
          효율성 증가
          처리량 증가
          처리비용 감소

      - 단점
          복잡하고 설계가 어려움.
          자원의 공유 문제
          하나의 쓰레드 문제 발생시 모두 문제 발생

 


교착상태(DeadLock)

: 멀티 쓰레드 중 쓰레드 간에 대기 상태가 종료되지 않아서 
무한정 대기만 하는 비정상적인 상태 

하나의 쓰레드를 끊어주거나, 모두 다 깨워주는 방법으로 교착상태를 해결한다. 

멀티 쓰레드 구현 방법 
 ① Tread 클래스 상속 
 ② Runnable 인터페이스 상속 

run() : 쓰레드 구현 
start() : 스케줄링 후 쓰레드 실행 

join() 
쓰레드 사용시 쓰레드 종료 전 다음 로직을 수행하면 
예기치 못한 오류가 발생한다. 
그러므로 join()을 사용하여 먼저 스케줄링 할 수 있다. 


Thread 클래스로 extends한 경우

package day22;

public class Thread1 extends Thread {
	String data;
	public Thread1() {}
	
	public Thread1(String data) {
		super();
		this.data = data;
	}

	@Override
	public void run() {
		//쓰레드 구현
		for (int i = 0; i < 10; i++) {
			System.out.println(data);
			//alt + shift + z
			try {Thread.sleep(500);} catch (Exception e) {;}
		}
	}
}

Runnable 인터페이스로 implements한 경우

package day22;

public class Thread2 implements Runnable {
	String data;
	
	public Thread2() {}
	
	public Thread2(String data) {
		super();
		this.data = data;
	}

	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(data);
			try {Thread.sleep(500);} catch (InterruptedException e) {;}
		}
	}

}

package day22;

public class ThreadTest {
	public static void main(String[] args) {
		//up casting
		Thread2 t1 = new Thread2("!");
		Thread2 t2 = new Thread2("?");
		
		//start로 스케줄링을 하기 위하여
		//Runnable객체를 생성자로 전달한다.
		Thread th1 = new Thread(t1);
		Thread th2 = new Thread(t2);
		
		//멀티 쓰레드(2개의 쓰레드)
		//전달 받은 Runnable 객체에 있는 run()을 스케줄링 해준다.
		th1.start();
		th2.start();
		
		try {
			//가장 먼저 작업하기 위해 join()을 사용한다.
			th1.join();
			th2.join();
		} catch (InterruptedException e) {;}
		
		//join()을 사용하지 않은 main쓰레드는 위의 작업이 모두
		//완료된 후 실행된다.
		System.out.println("main 메소드 종료");
		
//		Thread1 t1 = new Thread1("★");
//		Thread1 t2 = new Thread1("♥");
//		
//		t1.start();
//		t2.start();
//		t1.run();
//		t2.run();
		
	}
}

package zoo;

public class Animal implements Runnable {
	String sound;
	
	public Animal() {}
	
	public Animal(String sound) {
		super();
		this.sound = sound;
	}
	
	//자원
	public void makeSomeNoise() {
		for (int i = 0; i < 10; i++) {
			System.out.println(sound);
			try {Thread.sleep(500);} catch (InterruptedException e) {;}
		}
	}
	
	@Override
	public void run() {
		makeSomeNoise();
	}

}

package zoo;

public class Zoo {
	public static void main(String[] args) {
		//동물 3마리가 동물원에서 울음소리를 낸다.
		//두마리 동물은 동시에 10번 울고
		//남은 동물은 마지막에 10번 운다.
		//멀티 쓰레드로 구현한다(Runnable 사용)
		
		Animal[] animals = { new Animal("어흥"), 
				new Animal("으엉"), new Animal(".$#@#..")};
		
		Thread[] ths = new Thread[animals.length];
		
		for (int i = 0; i < ths.length; i++) {
			ths[i] = new Thread(animals[i]);
		}
		
		ths[0].start();
		ths[1].start();
		
		try {
			ths[0].join();
			ths[1].join();
		} catch (InterruptedException e) {;}
		
		ths[2].start();
	}
}

 


동기화(Synchronuzed)

: ① 특정 자원에 쓰레드가 동시에 접근하지 못하도록 제한하는 기법
  , ② 각 쓰레드를 사용자가 직접 제어하기 위해 사용하는 기법

 


은행 출금 예)

 

package atm;

public class ATM implements Runnable{
	int money = 10000;
	
	public void withdraw(int money) {
		this.money -= money;
		System.out.println(Thread.currentThread().getName() + "이(가) " + money + "원 출금");
		System.out.println("현재 잔액 : " + this.money + "원");
	}

	@Override
	public void run() {
		for (int i = 0; i < 5; i++) {
			synchronized (this) {
				withdraw(1000);
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					;
				}
			}
		}
	}

}

 


package atm;

public class CU {
	public static void main(String[] args) {
		ATM atm = new ATM();
		
		Thread mom = new Thread(atm, "엄마");
		Thread son = new Thread(atm, "아들");
		
		mom.start();
		son.start();
	}
}

 


빵 만드는 메소드가 실행, 빵이 10개 이상이되면 wait()하고 먹는 메소드가 실행된다.

빵이 0개가 되면 먹는 메소드가 멈추고 빵 만드는 메소드가 실행된다.

 

package bakery;

public class BakeryPlate {
	int breadCnt;
	int eatCnt;
	
	synchronized public void makeBread() {
		if (breadCnt > 9) {
			try {
				System.out.println("빵이 가득 찼습니다. 먹으세요.");
				wait();
			} catch (InterruptedException e) {;}
		}
		breadCnt++;
		System.out.println("빵을 1개 만들었습니다. 총 : " + breadCnt + "개");
	}
	
	synchronized public void eatBread() {
		if (eatCnt == 20) {
			System.out.println("빵이 다 떨어졌습니다.");
		}else if(breadCnt < 1) {
			System.out.println("기다리세요.");
		}else {
			breadCnt --;
			eatCnt++;
			System.out.println("빵을 1개 먹었습니다. 총 : " + breadCnt + "개");
		}
		//wait상태인 애가 this이다.
		this.notify();
	}
}

 


 

package bakery;

public class Maker  implements Runnable{

	private BakeryPlate bread = new BakeryPlate();
	
//	public Maker(BakeryPlate bread) {
//		super();
//		this.bread = bread;
//	}

	public BakeryPlate getBread() {
		return bread;
	}
	
	public void setBread(BakeryPlate bread) {
		this.bread = bread;
	}
	

	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			bread.makeBread();
			try {Thread.sleep(500);} catch (InterruptedException e) {;}
		}
		System.out.println("영업 종료");
	}


}

package bakery;

import javax.swing.JOptionPane;

public class Bakery {
	public static void main(String[] args) {
		Maker maker = new Maker();
		BakeryPlate bread = maker.getBread();
		
		Thread t = new Thread(maker);
		
		int choice = 0;
		String[] menu = {"빵 먹기"};
		
		t.start();
		
		while(true) {
			choice = JOptionPane.showOptionDialog(null,
					"", "파리바게트", JOptionPane.DEFAULT_OPTION,
					JOptionPane.PLAIN_MESSAGE, null, menu, null);
			
			if(choice == -1) {
				System.exit(0);
			}else {
				bread.eatBread();
			}
		}
	}
}

To Do List

Zoo에서
- 클래스로 만들 경우 : 각 동물마다 다른 기능을 가지고있고 다른 기능들을 쓰고자 할 때
- 객체로 만들 경우 : 각 동물의 같은 기능을 사용할 때

- 의존성에 대해서 한번 더 공부!

- up casting 꼭 다시 공부!

?) try/catch가 뭔지
  A) 원래 순서를 거스르는? 무언가를 쓸때는 try/catch를 사용. wait, sleep같은 메소드들!

 

    참고) https://coding-factory.tistory.com/280

 

?) Except와 In,..Except의 차


----- 단축키 -----

ctrl + shift + esc : 작업관리자

-------------------