Java

JAVA 예외처리, Thread

jmboy 2024. 4. 4. 17:39

Exception


1. Exception

  • 프로그램 실행 시 발생하는 다양한 형태의 오류.
  • 서버 → 오류가 난다고 서버가 꺼지면 안된다.
  • 만약 오류가 나고 코드로 처리하지 않으면 비정상 종료가 일어남.
    • Exception Handling 을 하게 되면 프로그램을 비정상 종료시키지 않고, 지속적으로 실행시킬 수 있다.
  • Java ⇒ 다양한 클래스의 Exception들로 제공된다.
    • 최상위 Exception → 상속 → 상속…
package exception;

public class ExceptionTest {
    public static void main(String[] args) {
        System.out.println("일부러 예외상황을 발생시켜 보자.");
//        int result = 10 / 0; // exception 발생 -> 비정상 종료
        //Exception이 발생하면 해당 Exception에 대한 클래스를 찾아서
        // Exception객체를 생성한다.
        // 자동으로 생성된 이 객체를 처리하지 않으면 프로그램이 비정상적으로 종료된다.
        // 만약 이 객체를 프로그램적으로 처리하면
        // ExceptionHandling해서 강제종료를 하지 않는다.
        try {
//            int result = 10 / 0;
            ExceptionTest t = null; // 객체 자체가 없다.
            System.out.println(t.toString());// null point exception

        } catch (ArithmeticException e ) {
            System.out.println(e.getMessage());
        } catch (NullPointerException e) {
            // 발생한 예외에 대한 처리코드가 나온다.
            System.out.println(e.getMessage());
        } finally {
            // 있으면 무조건 수행.
            System.out.println("무조건적인 수행 완료");
        }

    }
}

  • Exception이 터지면 해당 예외 객체는 e로 전달 됨.
  • Exception e 를 먼저 거는 순간 위에서 예외를 먼저 잡음.
  • → Exception e bad code
  • 추가적인 예외상황을 만들고 싶다.
  • ⇒ 내가 예외상황을 새롭게 정의하고 싶다. → Class를 만들면 된다. → Exception 을 상속.
  • Exception 객체가 있는 것과 Exception 이 발생한 것은 다른 것.
package exception;

class MyException extends Exception {
    
}
public class ExceptionTest2 {
    public static void main(String[] args) {
        try {
            throw new MyException();
        } catch (MyException e) {
            System.out.println("사용자 정의 오류 발생");
        }
    }
}


Thread


1. 기본 용어

많이 들어본 용어

  • process
  • thread
  • multitasking
  • multiprocessing (multithreading)

1. Process

  • 실행 중인 프로그램의 instance
  • 현재 실행 중인 프로그램을 지칭하는 용어.

프로세스가 동작하려면 OS로부터 Resource 를 할당받아야 한다..

  • Cpu time
  • 메모리
  • 디스크, file pointer들, 입출력 장치 등등..

2. Thread

  • 프로세스 안에 있는 프로그램의 실행 흐름을 담당.
  • 모든 프로세스는 1개 이상의 thread 를 가진다.
  • Process 내에서 실행되는 작은 실행단위.
  • Thread 는 process의 resource를 공유한다. ( memory )
    • thread 간의 데이터 통신이 가능하다.
    • 프로세스 간은 IPC로 통신
    ⇒ process의 효율성을 향상시킨다.
    • 빠르게 실행시키고, 메모리를 아낀다.
  • 만약 둘 이상의 Thread를 가진 process라면 multi-thread process라고 한다.

3. MultiTasking

  • CPU의 Core → process를 실행할 때 한 시점에 1개의 프로세스밖에 실행 못함.
    • 아주 세밀하게 시간을 나누어서 두 개를 번갈아가며 작업
  • 시분할 ( time slicing) 기법을 이용해 아주 짧은 시간 동안 여러 process를 번갈아 가면서 수행시켜 마치 동시에 실행되는 것처럼 보이게 하는 기법

4. multiprocessing

  • 두개의 작업을 동시에 실행 → core가 붙어야 실행이 될 수 있다. → 진짜 시간상 2개의 프로세스를 돌린다. Core가 2개 이상이어야 한다.
  • 서로 다른 core가 서로 다른 process를 시간적으로 동시에 실행시키는 개념.

5. MultiThreading

  • Thread를 시간상으로 동시에 실행 → core가 기본적으로 2개 이상이어야 한다.

6. HyperThreading

  • 1개의 코어로 2개이상의 thread를 돌림.

2. MultiThreading의 장점과 단점.

  • 장점
    • 프로세스의 효율을 높힘 - 빠르게 수행된다.
    • CPU와 resource를 효율적으로 사용함으로 process의 실행 효율을 높일 수 있다.
    • 사용자에 대한 응답성을 확보할 수 있다.
  • 단점
    • 리소스 공유 → 데이터 동기화 issue (항상 Synchronization) 에 신경을 써야 한다.
    • Dead Lock (교착 상태 - 리소스를 잡고 안놔주는 문제 ) 도 신경 써야 한다.

3. 구현.

  • Thread는 실행 단위 → call stack을 따로 가지고 있다. ( 2개 돌아가려면 stack 이 2개 생겨야함)
  • main method를 호출해서 실행시키는 thread를 우리는 main thread라고 부른다.
  • 프로그램의 종료는 프로그램 (process ) 안에서 생성한 모든 thread가 종료되어야 전체 process가 종료된다.
  • 언어적 차원에서 Thread 라는 class로 제공함. 이 클래스를 이용해야지 Thread를 생성할 수 있다.
  1. 첫번째 방법 → Thread 클래스를 상속, 사용자 정의 Thread class를 정의한 후 instance를 만들어서 사용하는 것. → 클래스간의 결합도가 높아진다.
  2. 두번째 방법 → Interface를 이용하는 방법
    • Java가 제공해주는 Runnable 이라는 interface를 구현해서 class를 만든 후,
    • 인스턴스를 생성. thread 생성자에 runnable 객체를 인자로 주어서 생성하면 thread가 만들어진다.
package thread;

class MyThread extends Thread {
    // 독립적인 실행 단위

    @Override
    public void run() {
        // thread의 실행 코드가 나온다.
        System.out.println("t1");
    }
}

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("t2");
    }
}

public class ThreadTest {
    // main thread
    public static void main(String[] args) {
        MyThread t1 = new MyThread(); // thread를 생성
        t1.start(); // Thread의 실행
        // start 는 non-blocking method이다.
        // start 는 thread scheduler 에게 thread를 실행시켜달라고 요청.
        MyRunnable r2 = new MyRunnable(); // thread를 생성
        Thread t2 = new Thread(r2);
        t2.start();

    }
}

  • non-blocking method
    • start 하는 순간 뒤에 일이 있어도 뒤의 일을 진행시킨다.
  • thread가 무엇이 먼저 실행될지 모르기 때문에 제어가 힘들다.
  • ⇒ 어느 정도 까지는 thread 제어가 가능하다.
package thread;

public class ThreadTest2 {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("너무 복잡..");
            }
        }).start(); 
        
    }
}

  • lambda 를 사용할 수 있다. ( 지속적으로 반복되는 코드 )
package thread;

public class ThreadTest2 {
    public static void main(String[] args) {
        new Thread(() -> System.out.println("너무 복잡..")).start();

    }
}


상태 전이도

  • thread객체를 만들면 new 로 객체들이 만들어짐. start() 하면 runnable 형태로 Thread queue에 들어감.
  • Thread Scheduler가 있다. ⇒ 실행할 Thread에 core를 붙혀줌.
  • Running 상태로 올라감.
  • Thread Scheduler 가 running 상태에 있는걸 본다. → 너무 많이 일을 하면 runnable 로 빼낸다.
  • run 이 끝나게 되면, Thread가 dead 상태가 된다. → 종료가 된다.
    • 종료된 thread는 다시 살릴 수 없다.