Java의 Thread

zihooy·2023년 5월 8일
1

Java Programming

목록 보기
15/21
post-thumbnail

Java 기본 문법 중 Thread에 대해 알아보자

🏹 Thread를 알아보기 전에... do you know upcasting?

본격적으로 Thread에 대해 알아보기 전에, 아래의 코드를 한번 살펴보자.

class A {
	void start() {
		System.out.println("start call");
		run();
	}
	void run() {
		System.out.println("A class Run");
	}
}
class B extends A {
	void run() {
		System.out.println("B class Run");
	}
}
public class hello {
	public static void main(String[] args) {
		A t = new B();	//업캐스팅
		t.start();	//결과: start call\nB class Run
	}
}

main함수에서 A t = new B(); 을 실행하여 업캐스팅을 한다.
그리고 나서 만들어진 객체 t의 메소드 start()를 호출하면,

start call
B class Run

위과 같은 결과가 나오게 된다 !
흐름을 따라가 보면 start()메소드는 class A에 정의되어 있고,
start()안에는 run()을 호출하는데
이 때 업캐스팅된 객체이므로 자식의 코드를 우선적으로 살펴보기 때문에
class A의 run()이 아닌, class B의 run()이 실행되는 것이다.

(혹시 업캐스팅의 개념이 헷갈린다면 Java의 업캐스팅 클릭!)

위 코드를 명확하게 이해하고 나면 아래의 Thread의 코드 실행도 이해하기 수월해진다.

🏹 Thread란?

참고 및 출처: TCP School
Thread는 Process 내에서 작업을 수행하는 주체이다.

그렇다면 Process란?
실행중인 프로그램
구체적으로 말하면, 사용자가 작성한 프로그램이 운영체제에 의해 메모리 공간을 할당받아 실행 중인 프로그램이다.

모든 Process에는 1개 이상의 Thread가 존재하여 작업을 수행한다.
만약 2개 이상의 Thread를 가진다면, 이를 Multi-Threaded Process라고 한다.

중요한 것은,
여러개의 Thread가 돌고 있을 때 어떤 Thread를 실행시킬지는 OS가 결정한다는 점이다!
= 내 맘대로 순서를 결정할 수 없음
= 여러개의 Thread가 동시에 실행되면 결과 순서를 내 맘대로 조작할 수 없음

자, 이제 Thread가 무엇인지 코드 예제를 통해 이해해보자.
아래의 코드는 위의 코드를 변형했다고 이해해도 좋다. 헷갈린다면 Tiger는 class B, Thread는 class A와 동일한 위치에 있다고 생각하자.

class Tiger extends Thread {	//Tiger = B, Thread = A
	public void run() {	
    //시작 2
		System.out.println(10000);
	}
}
public class hello {
	public static void main(String[] args) {
		Thread t = new Tiger();
		t.start();	//시작 1,2를 동시에 시작, 누가 먼저 실행되는지는 os에 따라 결정됨
		try {
			Thread.sleep(1000);
		} catch (Exception e) {
			
		}
		// 시작 1
		System.out.println(20000);
	}
}

위의 코드를 보면, Thread가 2개 존재한다.
(Tiger를 업캐스팅한 Thread와, 기본 main에서 동작하는 Thread)

앞서 언급한 것 처럼, 프로그램이 시작되는 순간 시작 1, 시작 2를 동시에 실행시키기 때문에 어떤 결과가 먼저 나올지는 알 수 없다.

돌릴 때마다 OS 맘대로 실행하기 때문에 결과가 달라지는 것을 확인할 수 있을 것이다.

마찬가지로 비슷한 예시를 한번 더 살펴보자.

class Tiger extends Thread {
	public void run() {	
		//시작1
		for (int i = 0; i < 10; i++) {
			System.out.println("코끼리"+ i);
			try {
				Thread.sleep(0);
			} catch (Exception e) {

			}
		}
	}
}
public class hello {
	public static void main(String[] args) {
		Thread t = new Tiger();
		t.start();	
		//시작2
		for (int i = 0; i < 10; i++) {
			System.out.println("호랑이"+ i);
			try {
				Thread.sleep(0);
			} catch (Exception e) {
				
			}
		}
	}
}
//시작 1,2를 동시에 시작, 누가 먼저 실행되는지는 os에 따라 결정됨

앞서 언급한 것 처럼, 프로그램이 시작되는 순간 시작 1, 시작 2를 동시에 실행시키기 때문에 for문 2개가 어떤 순서로 동작할지 모른다.

이는 단순히 시작1의 for문이 끝나고 시작2의 for문이 실행된다는 것이 아니라,
시작1의 for문 실행중에도 시작2의 for문이 실행되는 것이다.

결과를 보면 다음과 같이 나올 수 있다.

호랑이0
호랑이1
코끼리0
코끼리1
코끼리2
호랑이2
호랑이3
호랑이4
코끼리3
...

🏹 그렇다면 어떤 경우에 Thread를 활용할까?

A와 B프로그램이 둘 다 실행중이라고 가정해보자.
만약, A와 B프로그램 둘 다 1개의 Thread에서 실행중이라면?
A프로그램에 blocking이 생기면 B프로그램도 실행되지 못한다!

이처럼, 한(A) 프로그램이 blocking이 잡혀 있는 경우에도 다른(B) 프로그램은 돌아야 하는 경우 Thread를 활용하면 이 문제를 해결할 수 있다.

그런데, blocking이 잡혀있는 경우 외에도 blocking이 잡힌 것처럼 보이는 경우가 있다.
예를 들면 파일을 입력 받을 때, 용량이 큰 파일을 Read하는 시간동안은 blocking처럼 보일 수도 있다.
혹은 사용자에게 값을 입력 받을때, 사용자가 입력을 하지 않아 대기하는 시간동안은 blocking처럼 보일 수도 있다.

아래의 예시를 살펴보자.

class Lion extends Thread {
	public void run() {	
		new Scanner(System.in).nextInt();
		System.out.println(3);
	}
}
class Tiger extends Thread {
	public void run() {
		Thread l = new Lion();
		l.start();
		new Scanner(System.in).nextInt();
		System.out.println(2);
	}
}
public class hello {
	public static void main(String[] args) {
		Thread t = new Tiger();
		t.start();
		new Scanner(System.in).nextInt();
		System.out.println(1);
	}
}

코드를 살펴보면, 총 3개의 Thread가 존재함을 알 수 있다.
결론부터 말하자면 1)main 2)new Tiger() 3) new Lion() 이렇게 3개이다.

Thread를 잠깐 미뤄두고 코드의 흐름을 생각하면
1) main함수의 t.start()가 실행되며 Tiger class로 이동
2) Tiger class의 run()이 실행되며 l.start() 호출
3) Lion class의 run()이 실행

이렇게 진행되지만, 실제로는
1), 2), 3)이 동시에 실행되기 때문에 어떤 Thread가 먼저 실행될지는 알 수가 없다.

따라서 1)입력 -> 2)입력 -> 1)출력의 경우도 가능하게 된다.

그런데 만약 2)입력이 이루어지지 않는다면 ?
1)출력부터 실행되게 된다!

🏹 네트워크에서 Thread가 필요한 이유 (간단 ver.)

Client와 Server가 있다고 가정해보자.

Server는 기본적으로 blocking(접속을 받아주기 위한 Accept 함수)이 존재한다.
이와 동시에 Server는 다른 사용자와 소통중일 수도 있다.

따라서 Server의 Accept Thread, 통신 Thread는 따로 존재한다.

이어지는 포스팅에서 Thread를 활용하여 간단한 채팅 프로그램을 만들어 볼 계획이다.

profile
thisIsZihooLog

0개의 댓글