[JAVA] 쓰레드 ( Thread ) ②

DongGyu Jung·2022년 3월 26일
0

자바(JAVA)

목록 보기
45/60
post-thumbnail

🏃‍♂️ 들어가기 앞서..

본 게시물은 스터디 활동 중에 작성한 게시물로 자바의 정석-기초편 교재를 학습하여 정리하는 글입니다.
※ 스터디 Page : 〔투 비 마스터 : 자바〕

*해당 교재의 목차 순서와 구성을 참고하여 작성하며
각 내용마다 부족할 수 있는 내용이나 개인적으로 궁금한 점은
추가적인 검색을 통해 채워나갈 예정입니다.



🎏 싱글 쓰레드 & 멀티 쓰레드

❗ main 쓰레드

사실 쓰레드라고 해서
거리감이 느껴지고 처음보는 듯한 느낌이 들 수 있지만

여태까지 작업했던 내용들이 실행될 때에도 언제나 쓰레드와 함께였다.
프로그램이 실행되기 위해서는 작업을 위한 쓰레드가 최소한 하나가 필요하니 말이다.

지금까지는 동시에 여러가지 작업을 수행할 필요가 없었기에
별도의 쓰레드를 추가해서 사용하지 않은 것이고

우리가 학습하며 실행했던 코드들이 바로 쓰레드에서 수행된 것이다.
( main 쓰레드 ▶ " main 메서드 호출 " )

이것이 바로 멀티 쓰레드 프로세스가 아닌
싱글 쓰레드 프로세스인 것이고

main 메서드의 작업을 수행하는 쓰레드의 이름을
" main 쓰레드 "라고 부르는 것이다.

※ 쓰레드 (Thread) 종류

  • 사용자 쓰레드 ( user thread ) ex. main쓰레드 == " non-demon thread "
  • 데몬 쓰레드 ( demon thread ) : 보조 역할 쓰레드

직전 게시물의 마지막에
main 쓰레드의 main 메서드 작업이 끝났다 하더라도
다른 쓰레드의 작업이 끝나지 않았다면 프로그램이 종료되지 않는다 라고 했는데

위 용어를 사용해서 바꿔말하자면

"""
실행 중인 사용자 쓰레드가 하나도 없을 때, 프로그램이 종료된다
데몬 쓰레드는 사용자 쓰레드의 작업이 끝나면 강제적으로 사라진다.(뒤에서 더 알아보자)
"""

라고 할 수 있다.

class Practice {
	static long startTime = 0 ;
    
    public static void main(String args[]) {
    	Thread1 th1 = new Thread1();
        Thread2 th2 = new Thread2();
        
        th1.start();
        th2.start();
        startTime = System.currentTimeMillis();
        
        System.out.print("소요시간 : " + (System.currentTimeMillis() - startTime));
    }// main 메서드
}

class Thread1 extends Thread {
	public void run( ) {
		for(int i = 0; i<10 ; i++) {
            System.out.print(0);
		}
	}
}

class Thread2 extends Thread {
	public void run( ) {
		for(int i = 0; i<10 ; i++) {
            System.out.print(1);
		}
	}
}

/*
출력
000000000011소요시간 : 011111111
		 |(th1 종료)
         			   |(main 종료)
                       		   |(th2 종료)
*/

OS 스케줄러에 의해 쓰레드끼리 번갈아가면서
랜덤으로 작업들이 종료되는 것을 볼 수 있고
main이 종료되더라도 프로그램이 끝나지 않은 것을 볼 수 있다.

만약 main을 마지막에 끝내고 싶다면
try{} catch{}문과 join()메서드를 통해 설정할 수 있다.

class Practice {
	static long startTime = 0 ;
    
    public static void main(String args[]) {
    	Thread1 th1 = new Thread1();
        Thread2 th2 = new Thread2();
        
        th1.start();
        th2.start();
        startTime = System.currentTimeMillis();
        try{
	        th1.join(); // 작업이 끝날때까지 기다림
    	    th2.join();
        } catch(InterruptedException e) {}	
        
        System.out.print("소요시간 : " + (System.currentTimeMillis() - startTime));
    }// main 메서드
}

...
..

/*
출력
00000000001111111111소요시간 : 0
*/

🎭 싱글 vs 멀티

이전 글에서 " 멀티 쓰레딩 "의 장점을 알아봤었는데
살펴보면 시간에 대한 장점은 언급되어 있지 않다.

  • " 하나의 쓰레드로 처리하는 경우 "
    [ 작업 1 ]을 마친 후에 [ 작업 2 ]를 시작해서 끝내는 것

  • " 두 개의 쓰레드로 처리하는 경우 "
    [ 작업 1 ]과 [ 작업 2 ]를 짧은 시간동안 번갈아 가면서 수행해 동시(?)에 끝내는 것 ( 최소한의 종료시간 격차 )


물론 두 개의 쓰레드로 작업하는 경우
두 작업의 종료시간의 차이가 근소하다 보니

두 개의 작업을 더 빨리 끝낸 것 같은 느낌이 들 수 있지만
두 개의 작업을 처리하는데 소요된 시간은 거의 같다 .

오히려
멀티 쓰레딩이 시간을 조금 더 소요한다고 볼 수 있다.

그 원인은 바로
"" 쓰레드 간의 작업 전환 ( context switching ) "" 때문이다.

당연히 작업을 번갈아가면서 전환하면
하나의 작업만 집중한 경우보다 느릴 수 밖에 없다고 생각하면 된다.

그렇기 때문에
프로그램에 동시성이 중요한 경우가 아니고
단순 CPU만 사용해서 계산하는 작업이라면
싱글 쓰레드 프로그래밍이 더 효율적이다.



🚧 I/O 블락킹(blocking)

입출력 처리 (I/O)를 위해 다른 작업을 수행하지 않고 기다리는 것

앞서 두 쓰레드가 동시에 서로 다른 작업을 할 경우,
싱글 쓰레딩보다 멀티 쓰레딩이 효율적이라는 것을 알 수 있었다.

예를 들면

  • 사용자로부터 데이터를 입력받는 작업
  • 네트워크를 통해 데이터/파일 주고받는 작업
  • 프린터로 출력하는 작업
  • ....
    등 등이 있다.

만약 사용자에게 입력을 받는 작업을 수행하는데
또 다른 작업도 수행해야 하는 상황이라고 가정해보자.

《싱글 쓰레드》로 처리하게 되면
사용자가 입력을 할 때까지 다른 작업은 대기 상태로 유지된다.

대기 구간I/O 블락킹 구간인 것이다.

이렇게 되면 아무일도 못하고 기다리기만 하기 때문에
CPU를 효율적으로 사용하지 못하지만

《" 멀티 쓰레드 "》로 처리하게 된다면
I/O 블락킹 구간에
즉,
사용자의 입력을 기다릴 동안 다른 작업을 처리하게 된다.

그렇게 되면 CPU를 보다 효율적으로 활용할 수 있고
작업 처리 속도도 훨씬 빨라지는 이득을 얻을 수 있다.

0개의 댓글