본문 바로가기
JAVA공부/2-쓰레드

쓰레드의 구현과 실행

by 으노으뇨 2021. 10. 7.
728x90
반응형
SMALL

Tread클래스를 상속

이것은 하나만 상속받을 수 있는 자바언어 특성상 쓰레드를 상속받자니 조금 아쉽다.

class MyThread extends Thread{
	public void run(){ //쓰레드클래스의 run() 을 오버라이딩
    }
}

Rubbable 인터페이스 상속(이게좀더 좋다)

인터페이스를 상속받으니 다른 클래스를 상속을 받을 수 있기에

class MyThread2 implements Runnable{
	public void run()	{ //Runnable 인터페이스의 추상메서드 run()을 구현   
    }
}

두 상속된 것을 보면 (인터페이스와 클래스) 둘다 run()매서드를 가지고있다. 그래서 클래스를 쓰냐 인터페이스를 쓰냐 고민할 게없다. 둘다 같은 기능을 한다.! 

문서에서도 쓰레드 클래스에 애초에 러네이블이 있다..!

같은 기능 혐오스러운 코드...


한번 코드를 직접 작성하여 각 상속방법에 따라 어떤방법을 사용해야하는지 알아보자

package ch13.Thread;

public class ThreadEx1 {
	public static void main(String args[]) {
		ThreadTest_1 t1 = new ThreadTest_1();
		Runnable r = new ThreadTest_2(); //생성자 Thread 
		Thread t2 = new Thread(r);

		t1.start();
		t2.start();
	}

}

class ThreadTest_1 extends Thread {
	public void run() {
		for (int i = 0; i < 5; i++) {
			System.out.println(getName()); // 조상인 Thread의 getName()호출
		}
	}
}

class ThreadTest_2 implements Runnable {
	public void run() {
		for (int i = 0; i < 5; i++) { 
			System.out.println(Thread.currentThread().getName()); //현재 실행중인 Thread를 반환
		}
	}
}

쓰레드 2개를 만들었다. 하나는 쓰레드를 상속하고, 하나는 러너블 인터페이스를 구현했다.

t1이 시작을 하고 그이후 t2쓰레드가 시작되도록했다.

 

결과값은 다음과 같았다. 음, 내가 생각한것처럼 뭔가 동시? 다발적으로 진행된것같지 않다. 일꾼들에게 명령을 내렸으면 곧바로 샐행이 내려가지만 t1에게 명령을 내리고 t2에게 명령내리는 순간 컴퓨터 연산속도가 너무빨라서 다처리 해버려서 t1이후 t2가 순서대로 나온건지... 그래서 좀 많은 실험을 거듭해야겠다. 싶었따.

하루종일 F11로 실행시키면서 순서가 조금이라도 섞이는? 그런걸 기대하기 보단 한번 코드를 수정해보았다.

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

class ThreadTest_2 implements Runnable {
	public void run() {
		for (int i = 0; i < 700; i++) {
			System.out.print(1);
		}
	}
}

어짜피 쓰레드 이름과 0인지 1인지 나올껄 그냥 0과 1만 나오도록 수정했고, 출력방식도 ln을 해서 줄내림을 주는것보다 쭉 한줄로 나오도록 처리했다.

결과는 기가막혔다!!

대강 4~5번 실행했는데 이것과 비슷한 값을 얻었다. 

뭔가 드라마틱하게 0100110001 이렇게 나오진않았다. 컴퓨터 사양이 너무좋아서인가. 

그런건 상관없을것같지만 ...


쓰레드의 실행 - start()

쓰레드를 생성한 후 에 start()를 호출해야 쓰레드가 작업을 시작한다.

		ThreadTest_1 t1 = new ThreadTest_1();
		Runnable r = new ThreadTest_2(); //생성자 Thread 
		Thread t2 = new Thread(r);

		t1.start();
		t2.start();

t1, t2를 실행시켰는데 t1을 먼저 실행시켰다. 그후 t2이다. 사실 start했다고 쓰레드가 바로 시작하는 것은 아니다. 일단 실행대기 상태에 있다가 자신의 차례가 되어야 실행된다.  그리고 어느게 먼저 실행될지 모른다..!

-OS의 스케줄러가 작성한 스케줄에 의해 결정된다. 한낮 OS에서 돌아가는 하나의 프로세스에 불과한 자바버추얼 머신에서 OS스케줄러한테 맘대로 이래라 저래라 할 수 없기에..  

t1이 먼저 스타트했으니까 t1가 먼저 실행될 확률이 높을 뿐이다. 반드시 이런건 아니다.

따라서 지금 사진 처럼 1이 먼저나온다.즉 OS에 의존적인 면을 가지고 있다.

그런데 우리가 자바를 처음배울때 OS와는 조금 독립적으로 실행된다는게 자바버추얼머신이라고 배웠다.

OS에 종속적인게 몇가지가 있단다.. 그중에 하나가 쓰레드이다. 


start()와 run()

여기서 잠깐의 궁금증... 왜 스타트와 런이 따로있을까?

매안매서드에 스타를 호출하면 호출스택이 이렇게된다. 

스타트는 새로운 쓰레드를 생성하고, 이 쓰레드가 작업하는데 새로운 호출스택을 생성을 한다. (빈 컨테이너)

그리고 새로 생성된 호출스택에 run이 호출되고, 쓰레드가 독립된 공간에서 작업을 수행한다.

이때 스타트 매서드가 끝난다. (종료) 

이제는 호출 스택이 2개이므로 스케줄러 정한 순서에 의해 번갈아 가면서 실행 된다. 그리고 지금과 같은 모습이 된다.

각각의 쓰레드가 자기만의 호출스택을 가지고 실행이 되는것이고, 서로 독립적인 작업을 할 수 있게되는 것이다!

그래서 런을 호출하는게 아니고 스타트를 호출한다.

따라서 앞서 예제처럼 2개를 생성하면 저렇게 run이 호출된 호출스택이 2개가 있게되는거고 그게 대시상태고, 스케줄러에 의해 실행 여부를 판단받아 실행되게 되는것이다!

우리가 보통 main매서드가 수행을 마치면 프로그램이 종료되었으나, 쓰레드가 있을경우 쓰레드의 작업이 마쳐야 끝난다. 

더보기

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

쓰레드는 사용자 쓰레드와 데몬 쓰레드가 있다.

간단한 예시를 통해 보자

package ch13.Thread;

public class ThreadEx2 {
	public static void main(String args[]) {
		ThreadTest2_1 t1 = new ThreadTest2_1();
		t1.start();
	}
}

class ThreadTest2_1 extends Thread {
	public void run() {
	    System.out.println("쓰레드 시작?!");
		throwException();
	}

	private void throwException() {
		// TODO Auto-generated method stub
		try {
			throw new Exception();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

새로 생성한 쓰레드에 고의로 예외를 발생시키고 printStackTrace()를 이용해서 예외가 발생한 당시의 호출스택을 출력하는 예제이다. 

생성자쓰레드에 런매서드가 있고, 그곳에 출력문과 예외문이 있다. 그러니 정상작동이 될것이다. 

그렇다면 start매서드를 없이 실수로 run을 넣어놨다고 생각하고 실행하면 어떻게 될까?

package ch13.Thread;

public class ThreadEx3 {
	public static void main(String args[]) {
		ThreadTest2_1 t1 = new ThreadTest2_1();
		t1.run();
	}
}

class ThreadTest3_1 extends Thread {
	public void run() {
		System.out.println("과연될까?");
		throwException();
	}

	private void throwException() {
		// TODO Auto-generated method stub
		try {
			throw new Exception();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

실행은 되지않았다...

728x90
반응형
LIST

'JAVA공부 > 2-쓰레드' 카테고리의 다른 글

쓰레드 제어문(1)  (0) 2021.10.13
데몬 쓰레드와 쓰레드의 상태(실행제어)  (0) 2021.10.12
쓰레드의 우선순위, 그룹  (0) 2021.10.12
싱글쓰레드와 멀티쓰레드  (0) 2021.10.08
프로세스와 쓰레드  (0) 2021.10.07

댓글