Java/객체지향

[객체지향][쓰레드/thread] - 싱글 쓰레드와 멀티 쓰레드, 쓰레드의 I/O 블락킹

얄루몬 2022. 2. 28. 23:47

https://youtu.be/2eJc9ZdRe2c?list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp 

📖본 포스팅은 '자바의 정석 - 남궁성 저자' 님의 책과 유튜브 강의를 보고 작성되었습니다.


[main 쓰레드]

  • main 메서드의 코드를 수행하는 쓰레드를 main 쓰레드라고 한다.
  • 쓰레드는 '사용자 쓰레드'와 '데몬 쓰레드(=보조 쓰레드)' 두 종류가 있다.
    • 실행 중인 사용자 쓰레드가 하나도 없을 때 프로그램은 종료된다.
    • 즉, 메인 쓰레드가 실행을 맞치고 종료되었다고 해도 실행중인 쓰레드가 남아있다면 프로그램은 종료되지 않는다.
package javajungsuk;

public class Java13_11 {
	static long startTime = 0;
	
	public static void main(String[] args) {
		ThreadEx11_1 th1 = new ThreadEx11_1();
		ThreadEx11_2 th2 = new ThreadEx11_2();
		
		th1.start();
		th2.start();
		
		startTime = System.currentTimeMillis();
		
		try {
			th1.join();//main쓰레드가 th1의 작업이 끝날 때까지 기다린다.
			th2.join();//main쓰레드가 th2의 작업이 끝날 때까지 기다린다.
		} catch(InterruptedException e) {}
		
		System.out.print("소요시간: " + (System.currentTimeMillis()-startTime));
	}
}

class ThreadEx11_1 extends Thread{
	public void run() {
		for (int i = 0; i < 300; i++)
			System.out.print(new String("-"));
	}
}
class ThreadEx11_2 extends Thread{
	public void run() {
		for (int i = 0; i < 300; i++)
			System.out.print(new String("|"));
	}
}
  • 메인 쓰레드가 끝났다고 다른 쓰레드들이 끝나지 않았는데 프로그램이 종료되지 않는 예제를 살펴보았다.

 

 

[싱글 쓰레드와 멀티쓰레드]

[싱글 쓰레드의 경우]

package javajungsuk;

public class Java13_2 {

	public static void main(String[] args) {
		long startTime = System.currentTimeMillis();
		
		for(int i = 0; i < 300; i++)
			System.out.printf("%s", new String("-"));
		System.out.println("소요시간 1: "+(System.currentTimeMillis()-startTime));
		
		for(int i = 0; i < 300; i++)
			System.out.printf("%s", new String("|"));
		System.out.println("소요시간 2: "+ (System.currentTimeMillis()-startTime));
	}

}
  • 싱글 쓰레드로 돌릴 때 작업의 순서는 바뀌지 않고 순차적으로 진행 된다.

 

[멀티 쓰레드]

package javajungsuk;

public class Java13_3 {
	static long startTime = 0;
	public static void main(String[] args) {
		ThreadEx3_1 th1 = new ThreadEx3_1();
		th1.start();
		startTime =System.currentTimeMillis();
		
		for(int i = 0; i < 300; i++)
			System.out.printf("%s",new String("-"));
		System.out.println("소요시간 1: "+(System.currentTimeMillis()-startTime));
	}
}

class ThreadEx3_1 extends Thread{
	public void run() {
		for(int i = 0 ; i < 300 ; i ++)
			System.out.printf("%s",new String("|"));
		System.out.println("소요시간 2: "+(System.currentTimeMillis()-Java13_3.startTime));
	}
}
[출력값]
----------------------------------------------------------------------------------------------------------|||||||||||||||||||||||||||||||||||||||||||||||||||||||||-------------------------------------------------------------------------------------------||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||------------||||||||||||||||||||||||||||||-------------------------------------------------------------------------------------------|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||소요시간 1: 24 소요시간 2: 25
  • OS 스케줄러에서 실행 순서와 시간을 정하기 때문에 우리가 이를 지정할 순 없다. 그림은 저렇지만 실제로는 다르게 돌아간다.

[Context Switching]

  • 실행하는 작업이 변경하는 것을 Context Switching라고 하고 한 작업을 계속 쭉 진행하는 것보단 더 시간이 걸려서 멀티 쓰레드 작업을 하는 것이 시간이 더 걸린다.
  • 그러나 시간이 조금 더 걸려도 두 가지 작업을 한 꺼번에 할 수 있다는 것이 매우 큰 장점이다.
  • 작업을 좀 더 효율적으로 할 수 있다는 것이 매우 큰 장점이다 (=쓰레드의 I/O 블락킹(Blocking)

 

 

[쓰레드의 I/O 블락킹(Blocking)]

  • 입 출력 시 작업 중단을 I/O 블락킹(Blocking)이라고 한다.

[싱글 쓰레드]

package javajungsuk;

import javax.swing.JOptionPane;

public class Java13_4 {

	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); //1초간 시간 지연
			}catch(Exception e) {}
	}

}
  • 입력 전까지 아무 작업도 수행되지 않는 것을 확인할 수 있다.
  • 입력받는 작업과 카운트 작업이 동시 수행되는 것을 확인할 수 있다.

 

[멀티 쓰레드]

package javajungsuk;

import javax.swing.JOptionPane;

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

class ThreadEx5_1 extends Thread{
	public void run() {
		for (int i = 10; i > 0; i--)
			System.out.println(i);
			try {
				sleep(1000);
			}catch(Exception e) {}
	}
}
  • 입력 받는 작업과 카운트 다운 작업이 따로 분리되어 있음을 알수 있다.