개발/Java&Kotlin

[Java] 쓰레드(Thread)의 기초

devhooney 2022. 9. 14. 22:33
728x90

1.  프로세스와 쓰레드

- 프로세스는 실행 중인 프로그램을 말한다.

- 프로그램을 실행하면 OS로부터 메모리를 할당받아 프로세스가 된다.

- 프로세스는 데이터, 메모리 등의 자원과 '쓰레드'로 구성되어 있다.

- 자원을 이용하여 실제로 작업을 수행하는 것이 '쓰레드'이다.

- 모든 프로세스에는 최소한 하나 이상의 쓰레드가 존재하며, 두 개 이상일 경우 멀티 쓰레드라고 한다.

 

멀티태스킹과 멀티쓰레딩

- 멀티태스킹은 다중작업을 말한다. 멀티태스킹이 가능하면 여러 개의 프로세스가 동시에 실행될 수 있다.

- 멀티쓰레딩은 하나의 프로세스 내에서 여러 쓰레드가 동시에 작업을 수행한다.

 

멀티쓰레딩의 장단점

장점

- CPU의 사용률을 향상시킨다.

- 자원을 효율적으로 사용할 수 있다.

- 사용자에 대한 응답성이 향상된다.

- 작업이 분리되어 코드가 간결해진다.

 

단점

- 쓰레드 중 한 쓰레드만 문제가 있어도, 전체 프로세스에 영향을 준다.

- 쓰레드를 많이 생성할 경우 성능이 저하된다.(Context Switching)

 

 

2. 쓰레드의 구현과 실행

- 쓰레드를 구현하는 방법은 Thread 클래스를 상속받거나 Runnable 인터페이스를 구현하면 된다.

- Thread 클래스를 상속받으면 다른 상속이 불가능하기 때문에 Runnable 인터페이스 구현이 좋다.

 

class ThreadEx implements Runnable {
	public void run() {
        // 작업 내용
    	/.../
    }
}

 

- 예시

class ThreadExample {

    public static void main(String args[]) {
        Runnable r = new ThreadEx();
        Thread t = new Thread(r);

        t.start();
    }
}


class ThreadEx implements Runnable {
    public void run() {
    	for (int i = 0; i < 5; i++) {
        	System.out.println(Thread.currentThread().getName()); 
        }
    }

}

// currentThread() - 현재 실행중인 thread 리턴
// getName() - thread의 이름을 리턴

// 결과
// Thread-0
// Thread-0
// Thread-0
// Thread-0
// Thread-0

 

쓰레드의 실행 

- 쓰레드 실행은 start()로 한다.

- 쓰레드 실행 시 대기하다가 자신의 차례에서 실행된다.

- 한 번 실행이 종료된 쓰레드는 다시 실행할 수 없다. 다시 하기 위헤서는 새롭게 쓰레드를 생성하고 실행해야한다.

 

ThreadEx t = new Thread();
t.start();
t = new ThreadEx()l
t.start();

 

 

728x90

 

 

3. start()와 run()

- run()은 클래스에 선언된 메소드를 호출하는 역할

- run()실행 시 호출스택(call stack)에서 main 스택 위에 run 스택이 쌓인다.

 

- start()는 새로운 쓰레드가 작업을 실행하는데 필요한 호출스택을 생성한 다음에 run()을 호출해서, 생성된 호출 스택에 run()이 처음으로 올라가게 한다.

- 모든 쓰레드는 독립적인 작업을 위해 자신만의 call stack을 필요로 한다.

- 새로운 쓰레드를 생성하고 실행할 때 마다 새로운 call stack이 생성되고 쓰레드가 종료되면 작업에 사용된 call stack은 소멸된다.

 

https://intrepidgeeks.com/tutorial/java-basic-review-multithreaded-programming

 

- 쓰레드가 여러 개 일 경우 스케줄러가 순서를 정한다.

- 쓰레드는 사용자 쓰레드, 데몬 쓰레드 두 종류가 있다.

- 실행 중인 사용자 쓰레드가 하나도 없을 때 프로그램은 종료된다.

 

 

4. 싱글쓰레드와 멀티쓰레드

- 왼쪽은 하나의 쓰레드로 두 작업을 처리함 -> t1이 끝날 때 까지 t2는 대기

- 오른쪽은 두 개의 쓰레드로 두 작업을 처리함 -> t1과 t2가 번갈아 가며 작업

https://velog.io/@im_lily/%EC%9E%90%EB%B0%94%EC%9D%98-%EC%A0%95%EC%84%9D-Chapter-13-%EC%93%B0%EB%A0%88%EB%93%9C

- 두 개의 쓰레드가 번갈아 가며 작업하는 것을 Context Switching이라고 한다.

- 컨텍스트 스위칭 때문에 하나의 쓰레드보다 작업이 오래 걸리는 경우도 있다.

- 여러 쓰레드가 여러 작업을 동시에 진행하는 것을 병행이라고 한다.(concurrent)

- 하나의 작업을 여러 쓰레드가 나눠서 처리하는 것을 병렬이라고 한다.(parallel)

 

 

5. 쓰레드의 우선순위

쓰레드의 우선순위 지정하기

- 쓰레드의 우선순위는 setPriority()에 int값으로 정한다.

- 우선순위의 범위는 1~10이다.

- main 쓰레드의 우선순위는 5이다.

 

 

6. 데몬 쓰레드(daemom thread)

- 데몬 쓰레드는 일반 쓰레드의 작업을 돕는 쓰레드이다.

- 일반 쓰레드가 모두 종료되면 데몬 쓰레드는 강제적으로 종료된다.

- 예시로 가비지 컬렉터

- 데몬 쓰레드는 무한루프와 조건문을 이용해서 실행 후 대기하고 있다가 특정 조건이 만족되면 작업을 수행하고 다시 대기하도록 작성한다.

- 데몬 쓰레드가 생성한 쓰레드는 자동으로 데몬 쓰레드가 된다.

- 데몬 쓰레드는 setDaemon(true)를 호출해서 데몬 쓰레드로 변경하여 사용한다.

 

class ThreadEx implements Runnable {
    static boolean authSave = false;
    
    public static void main(String[] args) {
    
        Thread t = new Thread(new ThreadEx());
        t.setDaemon(true); // 이 부분이 없으면 종료되지 않음
        t.start();
        
        for (int i = 1; i <= 10; i++) {
        	try {
            	Thread.sleep(1000);
            } catch(InterruptedException e) {}
            System.out.println(i);
        	
            if (i == 5) autoSave = true;
        }
    	System.out.println("프로그램 종료!");
    }
    
    public void run() {
    	while (true) {
        	try {
            	Thread.sleep(3*1000); // 3초마다
            } catch(InterruptedException e) {}
            // autoSave의 값이 true이면 autoSave()를 호출한다.
            if (autoSave) autoSave();
        }
    
    }
    
    public void autoSave() {
    	System.out.println("자동저장!");
    
    }

}



// 실행 결과
// 1
// 2
// 3
// 4
// 5
// 6
// 자동저장!
// 7
// 8
// 자동저장!
// 9
// 10
// 프로그램 종료!

 

- setDaemon()은 반드시 start() 호출 전 실행되어야 한다.

 

 

728x90