본문 바로가기

Java/Java

(JAVA) 싱글쓰레드와 멀티쓰레드

두 개의 작업을 하나의 쓰레드로 처리 vs 두 개의 쓰레드로 처리

(a)의 경우에는 한 작업을 마친 후에 다른 작업을 시작하지만  (b)의 경우에는 th1 th2 가 번갈아가면서 작업을 수행한다.

  • (b)의 경우는 처리시간이 빠르기에 두 작업이 동시에 일어나는 것처럼 보인다.

(b)의 경우가 당연히 수행시간이 빠를 거라고 생각하지만 오히려 시간이 더 걸린다.

 

이유는 컨텍스트 스위칭에 시간이 걸리기 때문이다.

  

컨텍스트 스위칭 : 프로세스 혹은 쓰레드간의 전환을 의미

더보기

* 컨텍스트 스위칭(Context Switching)

     : CPU 내에 존재하는 레지스터들은 현재 실행 중인 프로세스 관련 데이터들로 채워진다. 

실행 중인 프로세스가 변경이 되면, CPU 내 레지스터들의 값이 변경되어야 하는데, 변경되기 전에 이전 프로세스가 지니고 있던 데이터들을 어딘가에 저장해 주어어야 한다.( 이어서 실행하기 위해 ). 그리고 새로 실행되는 프로세스가 아니라면 이전에 실행될 때 레지스터들이 지니고 있던 데이터들을 불러와서 이어서 실행해야 한다. 이 과정이 콘텍스트 스위칭이다. 

실행되는 프로세스의 변경 과정에서 발생하는 컨텍스트 스위칭은 시스템에 많은 부담을 준다.

레지스터 개수가 많을수록, 프로세스별로 관리되어야할 데이터 종류가 많을수록 더 부담이 된다.

컨텍스트 스위칭에 소요되는 시간을 줄이려면 저장하고 복원하는 콘텍스트 정보의 개수를 줄여주면 된다. 

 

* 메모리 구조 관점에서 본 프로세스와 쓰레드

: 자식 프로세스가 생성되고 난 다음에는 부모 프로세스가 가진 핸들 테이블은 상속되지만 모든 것(Code/data/heap/stack영역) 이 독립적으로 만들어진다. 이러한 메모리 구조를 지녔기에, 프로세스 간에 데이터를 주고받기 위해서는 IPC(Inter Process Communication)가 필요하다.

하지만 쓰레드를 생성하는 경우 메모리 구조는 다르다. 

프로세스가 쓰레드A와 B를 생성한 경우 쓰레드를 생성할 때마다, 해당 쓰레드만을 위한 ThreadStack영역(실행 흐름의 추가를 위한 최소 조건)만이 생성될 뿐, 나머지 영역(Code, Data, Heap)은 부모 프로세스 영역을 공유하고 있다. 쓰레드마다 스택을 독립적으로 할당해준다. 

https://agh2o.tistory.com/12

 

[Context Switching] 프로세스와 쓰레드에서의 컨텍스트 스위칭

* 프로세스란? 실행파일을 클릭했을 때, 메모리(RAM)할당이 이루어지고, 이 메모리공간으로 코드가 올라간다. 이 순간부터 이 프로그램은 '프로세스'라 불리게 된다. * 프로세스의 스케줄링? CPU는 하나인데, 동시..

agh2o.tistory.com

 


'-'와  ' | '를 출력하는 작업을 한 개의 쓰레드에서 처리하는 예제

public class SingleThread {
    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();

        for (int i=0;i<500;i++) {
            System.out.printf("%s", new String("-"));
        }
        System.out.println("소요시간 1 : "+ (System.currentTimeMillis() - startTime));

        for (int i=0;i<500;i++) {
            System.out.printf("%s", new String("|"));
        }
        System.out.println("소요시간 2 : "+ (System.currentTimeMillis() - startTime));
    }
}

실행결과


'-' 와  ' | ' 를 출력하는 작업을 두 개의 쓰레드에서 처리하는 예제 (main 쓰레드 & MultiThread2 쓰레드)

public class MultiThread {
    static long startTime = 0;

    public static void main(String[] args) {
        MultiThread2 th1 = new MultiThread2();
        th1.start();
        startTime = System.currentTimeMillis();

        for (int i=0;i<500;i++) {
            System.out.printf("%s", new String("ㅡ"));
        }
        System.out.println("소요시간 1 : "+(System.currentTimeMillis()-MultiThread.startTime));
    }
}
class MultiThread2 extends Thread{
    @Override
    public void run() {
        for (int i=0;i<500;i++) {
            System.out.printf("%s", new String("|"));
        }

        System.out.println("소요시간 2 : "+(System.currentTimeMillis()-MultiThread.startTime));
    }
}

실행 결과

거의 동시에 작업이 완료되었다.

 

싱글코어로 테스트해볼 수 없다는 점이 아쉽다...

 

 

  • 싱글 코어로 실행하였을 경우에는 아무리 멀티 쓰레드라 할지라도 하나의 코어가 번갈아가면서 작업을 하는 것이므로 절대 겹치지 않는다.
  • 멀티 코어로 실행하였을 경우에는 동시에 두 개의 쓰레드를 처리하므로 겹치는 부분이 발생한다.

자바가 OS에 독립적이라고 하지만 실제로는 OS에 종속적인 부분이 있다.

이 중 하나가 쓰레드이다. - OS의 스케쥴러에 의해 실행 순서와 실행시간이 결정되기 때문이다.


어떠한 경우에 멀티 쓰레드 프로세스가 유용할까?

각각의 쓰레드가 서로 다른 자원을 사용하는 경우에 해당한다.

위의 경우를 예로 들면 첫 번째는 싱글 쓰레드를 이용한 경우이다. 

해당 경우에는 점선에 보이는 것처럼 아무것도 하지않는 구간이 발생한다. 이는 A에 대한 사용자의 요청을 기다리는 구간이다.

 

두 번째 멀티 스레드를 이용한 경우를 보면

싱글 쓰레드를 사용하였을 때 요청을 기다리는 구간에 다른 쓰레드로 B의 요청을 처리한다.

 

여기서 주의할 점 두 가지

  • CPU는 특정 시간의 하나의 프로세스를 처리하는 것
  • 각각의 쓰레드는 같은 작업이 아닌 다른 작업을 처리한다는 것이다.

 

싱글 쓰레드 예시 - 사용자의 입력을 받는 작업 & 숫자를 출력하는 작업

public class MultiThread3 {
    public static void main(String[] args) {
        String input = JOptionPane.showInputDialog("아무 값이나 입력하세요...");
        System.out.println("입력하신 값은 "+input+"입니다.");

        for (int i=10;i>0;i--){
            System.out.println(i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

값 입력
실행결과

 

사용자의 입력을 받는 작업 이후에 숫자를 출력하는 작업을 진행하는 것을 볼 수 있다.

 

멀티 쓰레드 예시 - 사용자의 입력을 받는 작업 & 숫자를 출력하는 작업

public class MultiThread3 {
    public static void main(String[] args) {
        MultiThread4 multiThread4 = new MultiThread4();
        multiThread4.start();

        String input = JOptionPane.showInputDialog("아무 값이나 입력하세요...");
        System.out.println("입력하신 값은 "+input+"입니다.");

    }
}
class MultiThread4 extends Thread {
    @Override
    public void run() {
        for (int i=10;i>0;i--){
            System.out.println(i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

 

입력받는 도중에 숫자를 출력하는 쓰레드는 진행되고 있다.
실행결과

숫자를 입력하는 쓰레드가 실행 중에 값을 입력받는 쓰레드가 포함돼있는 것을 볼 수 있다.


쓰레드의 생명주기

https://12bme.tistory.com/65?category=682904

 

[병렬프로그래밍] 프로세스, 스레드 개념

프로세스란 무엇인가? - 프로세스 : 자기 자신만의 주소 공간을 갖는 독립적인(Self-Contained) 실행 프로그램 - 멀티 프로세스 : 두 개 이상의 프로세스가 실행되는 것. 프로그램이 여러개 띄워져 있는 형식. -..

12bme.tistory.com


코드 참조

https://github.com/mike6321/PURE_JAVA/tree/master/Thread

 

mike6321/PURE_JAVA

Contribute to mike6321/PURE_JAVA development by creating an account on GitHub.

github.com

 

'Java > Java' 카테고리의 다른 글

(JAVA) String.equals() 내부 뜯어보기  (0) 2020.01.21
(JAVA) 쓰레드 우선순위  (0) 2020.01.21
(JAVA) 쓰레드의 개요(2)  (0) 2020.01.19
(JAVA) 쓰레드의 개요 (1)  (0) 2020.01.19
(JAVA) 애노테이션 프로세서  (0) 2019.12.28