1
예외처리와 스레드[ 단원 08 ]
단원 08 예외처리와 스레드
학습목표❖ 예외와 예외처리를 이해하고 프로그래밍에 활용할 수 있다.
▪ • 에러와 예외의 차이와 클래스 계층구조▪ • 체크 예외와 비체크 예외의 차이와 처리 방법▪ • 새로운 예외 클래스의 생성과 사용 방법
❖ 스레드를 이해하고 스레드를 프로그래밍에 활용할 수 있다.▪ • 다중 작업과 스레드의 이해▪ • 클래스 Thread를 상속받아 처리하는 스레드 구현▪ • 인터페이스 Runnable을 구현하여 처리하는 스레드 구현
❖ 스레드 상태와 우선순위, 동기화를 이해하고 프로그래밍에 활용할 수 있다.▪ • 스레드 상태와 전이 방법▪ • 스레드 우선순위의 지정 방법▪ • 스레드에서 자원의 공유 문제와 동기화 처리▪ • Object의 wait( )와 notify( )를 사용한 동기화
3
단원 08 예외처리와 스레드 4
1. 예외처리 개요
단원 08 예외처리와 스레드
예외와 에러❖ 자바에서 오류: 에러(error)와 예외(exception)로 구별
▪ 예외• 자바 프로그램에서 실행 중에 발생할 수 있는 경미한 오류를 예외 • 적절한 처리 모듈을 추가하여 발생한 문제를 복구 가능 • IndexOutOfBoundsException과 같이 ◯ ◯ ◯ Exception 형태
▪ 에러• 메모리나 내부의 심각한 문제 • 복구가 불가능한 오류인 OutOfMemoryError, InternalError 등
▪ 에러와 예외를 모두 객체로 만들어 처리, 관련 클래스 계층 구조• 클래스 Throwable
– 하부로 예외인 Exception 클래스와 에러인 Error 클래스 • Exception 클래스 하부
– 다양한 예외를 위한 클래스
5
Section 1 예외처리 개요 p302
단원 08 예외처리와 스레드
다양한 예외의 발생❖ 예외가 발생하면
▪ 바로 프로그램이 중단되므로 발생한 이후의 프로그램을 실행되지 않음▪ 발생한 예외 클래스의 이름과 예외가 발생한 프로그램 소스와 줄 번호가 표시▪ NullPointerException
• 실제 변수에 저장된 객체가 null임에도 불구하고 객체의 멤버를 참조하려는 경우 발생 ▪ ArrayIndexOutOfBoundsException
• 배열에서 배열의 첨자 범위를 벗어난 첨자 사용
▪ ArithmeticException,• 0으로 수를 나누려 할 때 발생
▪ ArrayStoreException• 배열에 잘못된 유형의 객체를 저장하려 할 때 발생
▪ ClassCastException• 객체를 변환할 수 없는 유형으로 변환하려고 할 때 발생
▪ NegativeArraySizeException• 배열의 크기를 음수로 지정하는 경우 발생
6
Section 1 예외처리 개요
단원 08 예외처리와 스레드
실습예제❖ 8-1, 8-2
7
Section 1 예외처리 개요
단원 08 예외처리와 스레드
예외처리 구문 try❖ 예외처리(exception handling)
▪ 실행 중에 여러 이유로 예상하지 못했던 문제가 발생한 경우 이를 적절히 처리하는 모듈
❖ 예외처리 모듈▪ try ~ catch ~ finally 문장
• 예외 발생과 상관없이 finally의 블록은 실행 • catch와 finally 둘 중 하나는 옵션
8
Section 1 예외처리 개요
단원 08 예외처리와 스레드
실습예제❖ 8-3
▪ try 내부에서 예외가 발생하면• 더 이상 try 블록 내부의 나머지 문장은 실행하지 않음
9
Section 1 예외처리 개요
단원 08 예외처리와 스레드
catch 처리 순서❖ 여러 개의 catch 문을 이용하는 경우
▪ 프로그램이 실행되는 순간에 예외가 발생하면▪ 여러 개의 catch 문 중에서 위에서부터 순차적으로 catch(ExceptionType var) 문에서 ExceptionType 인자 유형을 검사
• 발생된 예외의 유형과 일치하거나 하위 클래스이면 먼저 만나는 catch 문 블록만을 실행
▪ 주의할 점• 여러 개의 catch구문에 기술하는ExceptionType이하위 클래스인 것부터 먼저 catch블록을 기술
10
Section 1 예외처리 개요
단원 08 예외처리와 스레드
실습예제 8-4
11
Section 1 예외처리 개요
❖ 예외 참조 변수인 e를 바로 출력하면 예외 클래스 이름과 메시지가 출력❖ 발생한 예외의 메시지만 알아보려면 e.getMessage() 메소드를 사용❖ 예외 처리를 하지 않은 경우 출력되는 모든 메시지를 보려면 e.printStackTrace() 메
소드를 사용
❖ 모든 예외 클래스는 Exception의 하위 클래스이므로 Exception 유형의 참조변수 catch 블록은 모든 종류의 예외를 처리할 수 있으므로 반드시 catch 블록의 마지막에 배치
단원 08 예외처리와 스레드 12
2. 체크 예외와 예외 생성
단원 08 예외처리와 스레드
예외 계층 구조❖ RuntimeException
▪ 그 하부 예외▪ ArithmeticException, NullPointerException,
ArrayIndexOutOfBoundsException, IndexOutOfBoundsException
13
Section 2 체크 예외와 예외 생성 p308
단원 08 예외처리와 스레드
비체크 예외와 체크 예외❖ 비체크 예외(unchecked exception)
▪ RuntimeException과 그 하부 예외가 발생할 가능성이 있는 코드들은 try ~ catch 문이 선택적
• RuntimeException, ArithmeticException, NullPointerException
❖ 체크 예외(checked exception)▪ 예외 중에서 RuntimeException과 그 하부 예외를 제외한 모든 예외
• FileNotFoundException – 존재하지 않는 파일을 처리
• ClassNotFoundException – 사용하려는 클래스의 이름을 잘못 기술
• DataFormatException – 입력한 데이터의 형식이 잘못
14
Section 2 체크 예외와 예외 생성
단원 08 예외처리와 스레드
체크 예외❖ 클래스 Class
▪ 클래스 Object의 하위 클래스로 응용 프로그램에서 실행 중인 클래스나 인터페이스를 대표하는 클래스
▪ Class의 메소드 중에 정적 메소드인 forName(className)• 인자인 className의 객체를 반환하는 메소드 • 인자인 className의 클래스가 없다면
– ClassNotFoundException 예외를 발생 • forName(className)을 호출하는 부분에서 반드시 예외처리를 수행
– 아니면 컴파일 에러 발생
15
Section 2 체크 예외와 예외 생성
단원 08 예외처리와 스레드
실습예제❖ 8-5❖ 메소드의 예외 확인
• 메소드 선언을 살펴보면 발생할 수 있는 예외를 알 수 있음 • 발생하는 예외가 체크 예외라면 메소드 호출 부분에서 예외처리가 없으면
– 컴파일 시간에 문법 오류가 발생
16
Section 2 체크 예외와 예외 생성
단원 08 예외처리와 스레드
체크 예외의 2가지 처리방법❖ 첫 번째 방법
▪ try~catch 구문 사용 방법
17
Section 2 체크 예외와 예외 생성
public class TryCheckedException { public static void main(String[] args) { //메소드 Class.forName()을 사용하려면 반드시 예외처리를 해야 함 try { System.out.println(Class.forName("java.lang.Object")); } catch (ClassNotFoundException ex) { System.out.println(ex); } } }
단원 08 예외처리와 스레드 18
❖ 두 번째 방법▪ 예외가 발생될 수 있는 구문이 속한 메소드에서 다시 예외를 전달(propagation)하는 방법
▪ 상위 메소드로 예외처리를 미루는 방법
public class PropagateCheckedException {
//메소드 선언에서 다시 예외 ClassNotFoundException의 발생을 전달 public static void main(String[] args) throws ClassNotFoundException {
//메소드 Class.forName()을 사용하려면 반드시 예외처리를 해야 함 System.out.println(Class.forName("java.lang.Object"));
} }
단원 08 예외처리와 스레드
예외 클래스 생성과 발생❖ 새로운 예외 클래스 정의
▪ Exception 을 상속받아 구현▪ 생성자에서 super(msg)로 구현▪ msg에 저장된 문자열은 메소드
getMessage()에 의해 반환
❖ 생성된 예외의 발생▪ 생성된 예외 클래스는 필요한 경우 예외를 발생(throws) 가능
• 예외를 발생시키는 부분에서는 new MyException("내가 만든 예외")
▪ 메소드 선언에서 throws MyException을 기술• 발생되는 예외가 여러 개라면 여러 예외 유형을 쉼표로 구분하여 기술
19
Section 2 체크 예외와 예외 생성
단원 08 예외처리와 스레드
실습예제 : 새로운 예외의 처리❖ 8-9
▪ super(msg)를 구현하지 않았다면
• getMessage()는 null을 반환
20
Section 2 체크 예외와 예외 생성
단원 08 예외처리와 스레드 21
3. 스레드 개요
단원 08 예외처리와 스레드
스레드(thread)❖ 프로그램 내에서 실행되는 프로그램 제어 흐름
▪ 프로그램의 내부의 실행 흐름인 스레드를 여러 개 만들 수 있다면• 여러 일을 동시에 처리하는 듯한 느낌
22
Section 3 스레드 개요 p314
단원 08 예외처리와 스레드
다중 작업과 다중 스레드❖ 다중 스레드(multi-thread) 프로그램
▪ 여러 개의 스레드를 이용하는 프로그램❖ 스레드
▪ 가벼운 프로세스(light-process)▪ 장점
• 하나의 프로그램 내부에서 실행되는 스레드는 프로세스보다 오버헤드가 적으면서 처리할 작업을 동시에 실행
23
Section 3 스레드 개요
❖ 다중 작업(multi-tasking)▪ 여러 프로그램을 동시에 실행시켜 서로 이동하면서 작업이 가능
❖ 프로세스(process) 란?▪ 실행되고 있는 프로그램▪ 프로세스마다 고유한 저장공간을 사용하며 독립적으로 실행
▪ 단점• 여러 프로세스를 실행하려면 프로세스 간의 정보 교환에 많은 시간이 소요
단원 08 예외처리와 스레드
스레드를 처리하는 첫 번째 방법❖ 클래스 Thread를 상속받아 구현하는 방법▪ 클래스 Thread를 상속받아 새로운 스레드를 정의
▪ Thread의 메소드 run()에서 스레드 작업을 재정의
▪ 단점• 다른 클래스를 상속받아야 하는 경우 이용할 수 없음
▪ 실행 방법• 객체를 생성한 후 메소드 start()를 호출하여 스레드를 시작
– 메소드 start()의 호출에 의해 스레드에 재정의된 run()이 수행
24
Section 3 스레드 개요
단원 08 예외처리와 스레드
스레드의 주요 메소드
25
Section 3 스레드 개요
단원 08 예외처리와 스레드
실습예제 8-10❖ 1에서 9까지 출력하는 스레드
26
Section 3 스레드 개요
SimpleThread.java
단원 08 예외처리와 스레드
스레드 이름 지정과 반환❖ 이름을 가진 스레드를 생성
▪ 메소드 setName()을 사용❖ 지정된 스레드의 이름을 반환
▪ 메소드 getName()을 사용❖ 스레드를 잠시 멈추게 하려면
▪ sleep(시간)을 이용, 지정된 인자는 천분의 1초
27
Section 3 스레드 개요
단원 08 예외처리와 스레드
실습예제 8-11
28
Section 3 스레드 개요
class IncThread extends Thread { //생성자 구현 public IncThread(String name) {
setName(name); //생성자 이름 지정 } public void run() {
for (int i = 1; i < 5; i++) { try {
sleep(50); // 50/1000 초 대기 System.out.print(getName() + ": " + i); System.out.println(", 활성화된 스레드 수: " + activeCount());
} catch (Exception e) { e.printStackTrace();
} }
} } class DecThread extends Thread {
public void run() { for (int i = 5; i > 1; i--)
try { sleep(50); // 50/1000 초 대기, 2000(2초)으로 수정가능 System.out.print(getName() + ": " + i); System.out.println(", 활성화된 스레드 수: " + activeCount());
} catch (Exception e) { e.printStackTrace();
} }
}
단원 08 예외처리와 스레드 29
public class ThreadTest { public static void main(String[] args) {
IncThread inc = new IncThread("증가 스레드"); inc.start(); DecThread dec = new DecThread(); dec.start();
} }
단원 08 예외처리와 스레드
인터페이스 Runnable❖ 인터페이스 Runnable
▪ 추상 메소드 run()으로 구성된 단순한 인터페이스▪ 스레드로 실행하려는 클래스
• 인터페이스 Runnable을 상속받아 메소드 run()에서 스레드 기능을 구현
❖ 클래스 Thread▪ Thread는 인터페이스 Runnable을 상속받아 메소드 run()을 재정의
30
Section 3 스레드 개요
package java.lang; public interface Runnable {
public abstract void run(); }
public class Thread implements Runnable { … }
단원 08 예외처리와 스레드
스레드를 처리하는 두 번째 방법❖ 인터페이스 Runnable의 run( ) 메소드 구현
▪ 스레드의 이름 반환• Thread.currentThread().getName()을 호출
❖ 스레드를 시작▪ 구현한 스레드의 객체 인자로 Thread를 생성
• 스레드 시작 메소드 start()를 호출
31
Section 3 스레드 개요
단원 08 예외처리와 스레드
실습예제 8-12
32
Section 3 스레드 개요
단원 08 예외처리와 스레드 33
4. 스레드 상태와 우선순위
단원 08 예외처리와 스레드
스레드 상태 6가지❖ 스레드의 상태
▪ 클래스 Thread 내부에 enum State으로 선언• 스레드는 객체가 생성되면 NEW라는 상태 • start()가 호출되면 RUNNABLE 상태로 이동
34
Section 4 스레드 상태와 우선순위 p322
단원 08 예외처리와 스레드
스레드 상태 전이❖ NEW : 스레드는 객체가 생성되면 이동되는 상태❖ RUNNABLE : 메소드 start()가 호출되면 이동❖ TERMINATED : 스레드가 완전히 종료된 상태
▪ 더 이상 NEW 또는 RUNNABLE 등의 다른 상태로 전이가 불가능한 상태❖ BLOCKED, WAITING, TIMED_WEIGHTING
35
Section 4 스레드 상태와 우선순위
단원 08 예외처리와 스레드
스레드 우선순위❖ setPriority()
▪ 스레드의 우선순위 지정❖ getPriority()
▪ 현재 값을 반환❖ 스레드의 우선순위
▪ 1에서 10까지 지정 가능
36
Section 4 스레드 상태와 우선순위
단원 08 예외처리와 스레드
실습예제 8-13❖ 스레드 우선순위는 특별히 지정하지 않으면
▪ 상수 NORM_PRIORITY의 값인 5
37
Section 4 스레드 상태와 우선순위
public class ThreadState implements Runnable { public void run() {
for (int i = 1; i < 10; i++) { try {
Thread.sleep(40);
System.out.print(Thread.currentThread().getState() + ", ");
System.out.println(Thread.currentThread().getName() + ": " + i);
} catch (InterruptedException e) {
System.err.pprintln("InterruptedException이 발생되어 스레드를 종료합니다. ");
return; } catch (Exception e) {
e.printStackTrace(); }
} } public static void main(String[] args) throws
InterruptedException { System.out.println("스레드의 모든 상태: 6 가지"); for (Thread.State c : Thread.State.values()) System.out.print(c + " "); System.out.println('\n');
Thread th = new Thread(new ThreadState()); System.out.println("기본 우선순위: " +
th.getPriority());
단원 08 예외처리와 스레드 38
5. 스레드 동기화
단원 08 예외처리와 스레드
다중 스레드의 문제❖ 다중 스레드 상에서 공유 자원의 처리 문제
▪ 예상하지 못한 문제 발생 가능성 존재• 스레드 A가 공유 자료를 처리하는 도중에 • 다른 스레드 B가 그 자료를 처리한다면
– 다중 스레드에서 수행해야 할 작업이 하나의 단위로 처리되지 않아서 발생할 수 있는 문제
39
Section 5 스레드 동기화 p326
단원 08 예외처리와 스레드
다중 스레드 구현❖ 은행 계좌 모의 구현
▪ 신청한 금액을 인출하는 메소드 withdraw()▪ 신청한 금액을 입금하는 메소드 deposit()
❖ 인터페이스 Runnable을 상속받는 스레드▪ 클래스 SyncTest는 은행계좌 객체 act 하나를 사용하여 20000원 이하의 금액에 대하여
• 입금(deposit)과 출금(withdraw)을 반복 처리 ▪ withdraw()는 어떠한 경우에도 잔고가 음수가 발생하지 않도록 의도
• 만일 계좌의 잔고가 0원 미만이면 계좌에 문제가 발생한 것이므로 스레드를 종료
40
Section 5 스레드 동기화
public class SyncTest implements Runnable { BankAccount act = new BankAccount();
public void run() {
while (true) { int amount = new Random().nextInt(10000); act.deposit(amount); act.withdraw(amount*2); if (act.balance < 0) {
System.out.printf("[%s] ", Thread.currentThread().getName()); System.out.println("잔고: " + act.balance + " => 오류 종료"); return;
} }
} …
}
단원 08 예외처리와 스레드
다중 스레드의 임계 영역❖ 임계영역(critical section)
▪ 다중 스레드에서 하나의 스레드가 배타적(exclusive)으로 공유 자원을 독점하도록 해야 하는 부분
❖ 임계영역의 실례▪ 하나의 스레드가 은행계좌의 인출 메소드 withdraw() 기능을 수행
• 중간에 다른 스레드가 들어와 일을 할 수 없도록 잠금(lock) 장치 필요 • 인출 기능을 모두 수행했다면 다른 스레드가 일을 하도록 잠금 장치를 해지(unlock) 해야 할 것
▪ 즉 다음 소스에서 1, 2, 3 세 개의 문장은 독점적인 실행 필요
41
Section 5 스레드 동기화
단원 08 예외처리와 스레드
동기화❖ 스레드 동기화(thread synchronization)
▪ 다중 스레드에서 임계영역의 독점적 처리 해결 방법❖ 동기화 방법 크게 2가지
▪ 메소드의 동기화• 메소드의 동기화는 메소드의 지정자인 키워드 synchronized를 기술
▪ 블록의 동기화• 블록의 동기화는 synchronized (Object) {…}
– 여기서 Object는 잠금 장치를 수행하는 객체
42
Section 5 스레드 동기화
단원 08 예외처리와 스레드
은행계좌의 동기화 문제❖ 임계 영역에서 자원의 공유로 인한 문제
▪ 두 스레드 Thread-0와 Thread-1• 동기화가 구현되지 않은 메소드 withdraw()에서 발생하는 문제
– 두 스레드가 각각 인출을 수행하므로 잔고가 음수가 되는 문제가 발생
43
Section 5 스레드 동기화
단원 08 예외처리와 스레드 44
Section 5 스레드 동기화package synchronize; import java.util.Random; class BankAccount {
int balance = 0;
//메소드 전체의 동기화 처리 public synchronized void withdraw(int money) {
if (money > 0 && balance >= money) { balance -= money; System.out.printf("%d 인출하여 현재잔고 %d입니다. %n", money, balance);
} else if (balance < money) System.out.println("잔고가 부족하여 인출할 수 없습니다.");
}
//블록 동기화로 메소드 전체의 동기화 처리 public void deposit(int money) {
synchronized (this) { if (money > 0) {
balance += money; System.out.printf("%d 입금하여 현재잔고 %d입니다. %n", money, balance);
} }
} }
단원 08 예외처리와 스레드 45
public class SyncTest implements Runnable {
BankAccount act = new BankAccount();
public void run() { //while (true) { for (int i = 0; i < 3; i++) {
int amount = new Random().nextInt(10000); amount = amount % 10 * 1000; System.out.printf("[%s] 금액=%d %n", Thread.currentThread().getName(), amount); act.deposit(amount); act.withdraw(amount * 2); if (act.balance < 0) {
System.out.printf("[%s] ", Thread.currentThread().getName()); System.out.println("잔고: " + act.balance + " => 오류 종료"); return;
} }
}
public static void main(String[] args) { Runnable r = new SyncTest(); new Thread(r).start(); new Thread(r).start();
} }
단원 08 예외처리와 스레드
메소드 wait( )와 notify( ), notifyAll( )의 이해❖ Object의 메소드 wait()와 notify(), notifyAll()을 사용
▪ 스레드 동기화에서 동기화 효율을 높이는 방안▪ 메소드 wait()
• 동기화 블록에서 객체의 특정한 작업을 위해 처리 중인 스레드를 WAITING 또는 TIMED_WAITING 상태로 이동
▪ notify() 또는 notifyAll()• 다시 스레드 상태를 RUNNABLE로 이동시켜 스레드 작업을 다시 수행 시킴
▪ 특징• Object 클래스의 메소드이므로 모든 객체에서 사용 가능 • 키워드 synchronized를 사용하는 동기화 내부에서만 사용 가능
46
Section 5 스레드 동기화
단원 08 예외처리와 스레드
메소드 wait( )와 notify( ), notifyAll( )의 사용❖ 메소드 wait()
❖ notify() 또는 notifyAll()
47
Section 5 스레드 동기화
단원 08 예외처리와 스레드 48
Section 5 스레드 동기화package wait; import java.util.Random; class BankAccount {
int balance = 0; int diff = 0;
public synchronized void withdraw(int money) {
if (money < 0) { System.out.println("인출 금액이 잘못됐습니다."); return;
} int count = 0; while (balance < money) {
System.out.printf("[%s] ", Thread.currentThread().getName()); // 지속적으로 잔금이 부족하여 메소드 종료 if (++count > 3) {
System.out.println("잔액이 부족하여 출금처리 못하고 종료합니다."); return;
}
System.out.printf("%16s", "wait(1000) 호출: "); System.out.printf("인출요구금액=%6d, balance=%6d %n", money, balance); try {
// wait(); wait(1000);
} catch (InterruptedException e) { System.err.println(e);
} } System.out.printf("[%s] ", Thread.currentThread().getName()); balance -= money; System.out.printf(" %12s 정상인출금액=%6d, balance=%6d %n", "정상 출금처리:",
money, balance); }
public synchronized void deposit(int money) {
if (money < 0) { System.out.println("입금 금액이 잘못됐습니다."); return;
} balance += money; System.out.printf("[%s] ", Thread.currentThread().getName()); System.out.printf("%16s", "notify() 호출: "); System.out.printf("계좌입금금액=%6d, balance=%6d %n", money, balance); // notify(); notifyAll();
} }
단원 08 예외처리와 스레드 49
public class SyncTest implements Runnable { BankAccount act = new BankAccount();
public void run() {
for (int i = 1; i < 3; i++) { int amount = (int) (new Random().nextDouble() * 5 + 1) * 10000; act.deposit(amount); amount = (int) (new Random().nextDouble() * 5 + 1) * 10000; act.withdraw(amount);
} }
public static void main(String[] args) {
Runnable r = new SyncTest(); new Thread(r).start(); new Thread(r).start();
} }
50
[ Add your company slogan ]
Thank You !
Top Related