관리 메뉴

기억하기 프로젝트

Thread, Join, Runnable 본문

개발이야기/Java

Thread, Join, Runnable

sy89 2017. 2. 22. 21:56

최근에 쓰레드 관련 프로그램을 작성하면서, 부족하다고 느꼈던 부분을 다시 공부해 보자는 마음으로 스레드의 개념을 다시 들춰보았다.


Thread

보통 스레드를 공부하게 되면 동시에 나오는 개념이 프로세스인 것 같다. 프로세스는 운영체제로부터 자원을 할당받아 실행되는 흐름이라고 본다면, 스레드는 그 프로세스가 할당받은 자원을 이용하는 개념이라고 보면 될 듯 하다.

또한, 한 개의 프로세스는 한 가지의 일을 하지만 스레드를 사용하면 한 프로세스 내에서 동시다발적으로 일을 수행할 수 있다. 

그렇기 때문에, 빠른 처리가 필요하거나 많은 데이터를 처리해야할 때 스레드를 이용한 프로그램 소스를 흔히 볼 수 있다.

먼저, 간단한 예제를 통해 확인해보도록 하자.

public class MyThread extends Thread {
int seq;
public MyThread(int seq) {
this.seq = seq;
}

@Override
public void run() {
System.out.println(this.seq + " thread start");

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}

System.out.println(this.seq + " thread end");
}

public static void main(String[] args) {
System.out.println("main start");

for (int i = 0; i < 5; i++) {
Thread thread = new MyThread(i);
thread.start();
}

System.out.println("main end");
}
}

위의 예제는 5개의 스레드를 각각의 seq를 부여해서 생성하여, 어느 시점에 시작되고 끝나는지를 확인하기 위한 예제이다.

(시작과 종료사이에 1초의 간격을 부여하였다)

MyThread 클래스가 Thread를 상속받아 Thread클래스의 run메소드를 구현하고, 실행시 Thread객체를 start() 해주면 

결국 내부적으로 run() 메소드를 수행한다.

수행 결과를 이미지를 통해 확인해 보면, 각각의 스레드가 순차적이 아닌 동시다발적으로 수행되어버린다는 것을 알 수 있다.

심지어, t.start()로 run()내부 로직이 수행도 되기 전에 'main end' 메시지 출력이 수행되고 있다..


Join

위의 예제에서는 스레드가 종료 되기도 전에 main이 종료되는 현상을 볼 수 있었는데, Thread의 join()메서드를 사용하면 모든 스레드가 종료된 후에 main이 종료될 수 있도록 실행시킬 수 있다. 

main메서드만 수정을 해서 join()메서드를 사용하도록 해 보자.

public static void main(String[] args) {
System.out.println("main start");

List<Thread> threads = Lists.newArrayList();

for (int i = 0; i < 5; i++) {
Thread thread = new MyThread(i);
thread.start();
threads.add(thread);
}

for (int i = 0; i < 5; i++) {
Thread thread = threads.get(i);
try {
thread.join();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
System.out.println("main end");
}

스레드를 생성하여 실행시킨 후, ArrayList객체에 담고

다시 ArrayList객체에 담겨진 스레드를 하나씩 꺼내서 join메서드를 호출하여 스레드가 종료될 때 까지 대기할 수 있도록 한다.

결과는 다음과 같다.



Runnable

스레드 프로그램을 작성할 때 보통 이 글의 첫 번째 예제에서와 같이 Thread 클래스를 상속받거나, Runnable 인터페이스를 구현하여 작성하게 된다. 위에서 만든 스레드 예제를 Runnable 인터페이스로 구현해보도록 하자.

public class MyThread2 implements Runnable {
int seq;
public MyThread2(int seq) {
this.seq = seq;
}

@Override
public void run() {
System.out.println(this.seq + " thread start");

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}

System.out.println(this.seq + " thread end");
}

public static void main(String[] args) {
System.out.println("main start");

List<Thread> threads = Lists.newArrayList();

for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new MyThread2(i));
thread.start();
threads.add(thread);
}

for (int i = 0; i < 5; i++) {
Thread thread = threads.get(i);
try {
thread.join();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
System.out.println("main end");
}
}

이전 소스와의 차이점은 다음과 같다.

1. Runnable 인터페이스를 implements하여 run()메소드 구현을 강제화 한 것

public class MyThread2 implements Runnable


2. 스레드 생성할 때, Thread생성자에 Runnable를 구현한 클래스를 넘겨준 것.

Thread thread = new Thread(new MyThread2(i));

Runnable 인터페이스를 사용하여 스레드를 구현하는 장점이라고 한다면 위의 소스와 같이, Thread생성시 넘겨주는 객체를 바꿔낄 수 있다는 점? 흔히 인터페이스를 사용하여 전략을 바꿔낄 수 있는 Strategy 패턴을 스레드 프로그램에서도 사용할 수 있다고 본다!



소스&내용 참고 : https://wikidocs.net/230




'개발이야기 > Java' 카테고리의 다른 글

Java VM 옵션  (0) 2014.09.21