프로그래밍/Java

자바 프로그래밍 / Thread와 Runnuble

배기니어 2021. 2. 13. 20:39

지난 안드로이드 소켓 프로그래밍에서 쓰레드를 이용해 서버에 접속했다.

 

2021/01/31 - [프로그래밍/Android Java] - 안드로이드 프로그래밍 / 멀티쓰레드 #1

 

안드로이드 프로그래밍 / 멀티쓰레드 #1

지난 프로그래밍에서 안드로이드 디바이스가 소켓을 생성하는 과정에서 문제가 발생했다. 지난 글 참고 2021/01/29 - [프로그래밍/Android Java] - 안드로이드 소켓 프로그래밍 / 클라이언트 프로그래

bagineer.tistory.com

2021/01/31 - [프로그래밍/Android Java] - 안드로이드 소켓 프로그래밍 / 클라이언트 - 서버 접속 #2

 

안드로이드 소켓 프로그래밍 / 클라이언트 - 서버 접속 #2

앞서 프로그래밍했던 클라이언트 소켓은 메인쓰레드에서 서버에 연결을 시도했기 때문에 에러가 발생했다. 그래서 이번에는 쓰레드를 생성하여 접속을 시도하는 방법을 적용해보자. - 지난글 2

bagineer.tistory.com

 

자바에서는 쓰레드를 생성하는 방법에 두 가지가 있다.

1. Thread 클래스 상속을 통한 새로운 클래스 작성

2. Runnable 인터페이스로 구현한 새로운 클래스 작성

 

이번 글에서는 두 방법에 대해 공부하고 차이점을 알아보자!

 

 


 

Thread 클래스 상속

 

먼저 Thread 클래스를 상속받아 새로운 클래스를 작성하여 쓰레드를 생성하는 방법은 지난 멀티쓰레드 프로그래밍에서 해보았다.

새로운 클래스 작성 시 extends Thread를 이용하여 Thread 클래스를 상속하고, run 메소드를 재정의하면 된다.

 

package thread;

public class Example {
	
	public static void main(String[] args) {
		MyThread thread = new MyThread();
		thread.start();
	}
}

class MyThread extends Thread {
	
	public void run() {
		for (int i=0; i<5; i++) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(i);
		}
	}
}

 

 


 

Runnable 인터페이스 구현

 

다음으로 Runnable 인터페이스를 이용해 쓰레드를 생성해보자.

Thread 클래스를 상속받아 작성하는 방법과 크게 다르지 않다.

extends Thread 대신 implements Runnable을 쓰고 똑같이 run 메소드를 정의하면 된다.

쓰레드를 생성하는 부분에서는 좀 차이가 나는데, 먼저 작성한 클래스의 객체를 생성한다.

그리고 그 객체를 쓰레드의 생성자에 전달하여 새로운 쓰레드 객체를 생성한다.

마지막으로, 생성한 쓰레드 객체를 실행하면 쓰레드가 실행된다.

 

package thread;

public class Example {
	
	public static void main(String[] args) {
		RunnableThread rThread = new RunnableThread();
		Thread thread = new Thread(rThread);
		thread.start();
	}
}

class RunnableThread implements Runnable {
	
	public void run() {
		for (int i=0; i<5; i++) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(i);
		}
	}
}

 

 


 

차이점

 

구글링하면서 공부한 결과 차이점에 대해 정리하는 게 가장 어려웠다.

그나마 알아본 차이점들을 정리하면 다음과 같다.

 

1. Thread 상속에 비해 Runnable 구현이 더 확장성이 좋다.

 

이전에 작성했던 extends와 implements의 차이를 설명하는 글에서 클래스 상속과 구현의 차이를 알아보았다.

그 얘기의 연장선같은데, 자바에서는 다중 상속이 불가능하므로, Thread를 상속받을 경우에는 다른 클래스 상속이 불가능하여 확장이 용이하지 않다. 그러나 Runnable 구현을 통해 클래스를 작성한다면 쓰레드를 구현함과 동시에 다른 클래스 상속이 가능하므로 확장성이 더 좋다.

 

2. Runnable 구현이 더 재사용성이 좋다.

 

이건 솔직히 잘 모르겠다. 재사용성이란 말이 코드의 재사용을 말하는건지 객체의 재사용을 말하는 건지 누구 하나 제대로 설명해놓은 글을 못 찾았다.

내 나름대로 해석을 해보자면 코드의 재사용성보다는 객체의 재사용성에 조금 더 가까운 말인 것 같다.

코드의 재사용성은 이전에 작성한 변수나 메소드를 다시 작성하지 않고 가져다 쓸 수 있을 때, 즉 상속이 이루어질 때 재사용성이 높다고 하며, Runnable 인터페이스 구현 시 run 인터페이스를 새로 작성해야 하기 때문에, 코드의 재사용성은 좋다고 생각할 수 없다.

 

그러나 객체 생성의 관점에서 보면 Thread 상속을 통해 구현한 클래스의 객체는 한 번 생성하여 실행하면 다시 활용할 수 없다. 같은 작업을 하고자 한다면 새로운 객체를 다시 생성하여 실행해야 한다.

아래 작성한 코드와 같이 하나의 객체를 두 번 실행하면 에러가 발생한다.

 

package thread;

public class Example {
	
	public static void main(String[] args) {
		MyThread thread = new MyThread();
		thread.start();
		thread.start();	// error
	}
}

class MyThread extends Thread {
	
	public void run() {
		for (int i=0; i<5; i++) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(i);
		}
	}
}

 

반면, Runnable 구현을 통해 작성한 클래스의 객체는 한 번 생성하여 다시 활용할 수 있다.

아래 코드와 같이 RunnableThread 객체 rThread는 한 번만 생성하면 쓰레드를 몇 개를 생성하더라도 계속해서 활용이 가능하다.

따라서 재사용성이 좋다는 말은 이러한 부분에서 좋다는 말이 아닐까 싶다.

그러나 이렇게 해도 쓰레드 객체는 새로 생성해야 하기 때문에, 과연 재사용성이 좋은 것이 맞는것인지 의구심이 든다.

 

package thread;

public class Example {
	
	public static void main(String[] args) {
		RunnableThread rThread = new RunnableThread();
		Thread thread1 = new Thread(rThread);
		thread1.start();
		Thread thread2 = new Thread(rThread);
		thread2.start();
	}
}

class RunnableThread implements Runnable {
	
	public void run() {
		for (int i=0; i<5; i++) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(i);
		}
	}
}

 

 


 

요약

 

Thread 상속보다 Runnable 구현을 통한 쓰레드 작성이 더 확장성이 좋고 재사용성(?)이 좋다.

따라서 Thread보다는 Runnable 인터페이스를 이용해 쓰레드 작성을 권장한다!