Inor

[JAVA] Runnable (Runnable Interface 사용법) 본문

Computer Engineering/Java

[JAVA] Runnable (Runnable Interface 사용법)

Inor 2017. 7. 24. 17:41

 Runnable


 자바에서 스레드를 구현할 때 Thread Class와 Runnable Interface를 이용 합니다. 둘의 뚜렷한 차이점은 클래스와 인터페이스라는 구현된 방식에서 발생 합니다. 자바에서는 한개 이상의 클래스를 상속 받을 수 없습니다. 다중 상속을 언어 차원에서 막았기 때문 입니다. 그렇기 때문에 Thread 클래스를 상속(extends) 받아서 스레드를 구현한 자식 클래스는 다른 클래스를 상속(extends) 받을 수 없습니다. 그러나 Runnable 인터페이스를 상속(implements) 받은 자식 클래스는 다른 클래스를 상속(extends) 받을 수 있습니다. 즉, 엄밀히 따지면 다중 상속은 아니지만 효과를 낼 수 있습니다. Runnable  인터페이스를 상속 받은 클래스도 Thread 객체를 만들어서 스레드로 사용하기 때문에 성능에서의 차이점은 없는 것 같습니다. 아래는 Runnable 인터페이스를 이용해서 구현된 코드 입니다. 이전에 Thread 클래스를 상속 받아서 구현 했었던 코드와 비슷하기 때문에 코드의 배경에대한 설명은 최대한 줄이도록 하겠습니다.

import java.util.ArrayList;
import java.util.Random;

class Mcdonald {
	private int numOfBigmac;

	public Mcdonald(int numOfBigmac) {
		this.numOfBigmac = numOfBigmac;
	}

	// 빅맥을 주문할 때마다 1씩 줄여줬습니다.
	public int orderBicmac() {
		synchronized (this) {
			if (numOfBigmac > 0) {
				numOfBigmac--;
				return 1;
			} else {
				System.out.println("빅맥이 없습니다");
				return 0;
			}
		}
	}

	// 남아있는 빅맥의 양을 보여줍니다.
	public void showNumOfBicmac() {
		System.out.println("남은 빅맥 : " + numOfBigmac);
	}
}

class Customer implements Runnable {
	private int id;
	private Mcdonald curMcdonald;
	private int numOfBigmac;

	public Customer(int id) {
		this.id = id;
		numOfBigmac = 0;
	}

	// Runnable를 상속 받으면서 오버라이딩한 메서드 입니다.
	@Override
	public void run() {
		System.out.println("Customer ID : " + id + " 주문중");
		Random r = new Random(System.currentTimeMillis());
		try {
			long time = r.nextInt(6000);
			Thread.sleep(time);
			// 빅맥을 획득 했습니다.
			numOfBigmac += curMcdonald.orderBicmac();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("Customer ID : " + id + " 주문 완료");
	}

	// 최근(current) 할당 받은 맥도날드 객체(mcdonald)를 참조 합니다.
	public void setGasStation(Mcdonald mcdonald) {
		curMcdonald = mcdonald;
	}
}

public class RunnableTest {

	public static void main(String[] args) {
		// Customer 객체들을 저장할 자료구조를 생성 했습니다.
		ArrayList<Thread> customers = new ArrayList<Thread>();
		// Customer 객체가 주문할 수 있도록 Mcdonald 객체를 만들었습니다.
		Mcdonald inorMcdonald = new Mcdonald(20);
		// 새로운 Customer 객체를 만들고 Mcdonald 객체를 참조하도록 설정 합니다.
		for (int i = 0; i < 10; i++) {
			Customer tempCustomer = new Customer(i);
			//Runnable 인터페이스를 상속 받은 tempCustomer를 이용해서 스레드를 생성 합니다.
			Thread tempThread = new Thread(tempCustomer);
			tempCustomer.setGasStation(inorMcdonald);
			//생성된 스레드를 실행 시킵니다.
			tempThread.start();
			//생성된 스레드를 ArrayList에 추가 합니다.
			customers.add(tempThread);
		}

		// Join
		// tempThread 쓰레드를 조인 합니다.
		for (int i = 0; i < customers.size(); i++) {
			try {
				Thread tempThread;
				tempThread = customers.get(i);
				tempThread.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		inorMcdonald.showNumOfBicmac();
		System.out.println("메인 스레드 종료");

	}

}

 Mcdonald 클래스와 Customer 클래스가 있고 Customer 객체에서 Runnable 인터페이스를 상속 받아서 run() 메서드를 재정의 했습니다. Customer 클래스의 run 메서드에서 주문을 시작 합니다. join에대한 정확한 설명은 여기서 하지 않겠습니다. join을 하는(tempThread.join()) 이유는 생성된 스레드가 끝나기 전에 메인 스레드가 끝나기 때문에 했습니다. 여기서 중요한 부분은 Runnable 인터페이스를 상속 받은 Customer 클래스가 어떻게 스레드로 실행(Thread.start()) 되는지를 주목해서 봐야 합니다. 아래는 그 부분에대한 코드 입니다. 실제 위치는 메인 메서드 내부에 있습니다.


		//Car 객체들을 저장할 자료구조를 생성 했습니다.
		ArrayList customers = new ArrayList();
		// Car 객체에 주유할 GasStation 객체를 만들었습니다.
		Mcdonald inorMcdonald = new Mcdonald(20);
		// 새로운 Car 객체를 만들고 GasStation 객체를 참조하도록 설정 합니다.
		for (int i = 0; i < 10; i++) {
			Customer tempCustomer = new Customer(i);
			//Runnable 인터페이스를 상속 받은 tempCustomer를 이용해서 스레드를 생성 합니다.
			Thread tempThread = new Thread(tempCustomer);
			tempCustomer.setGasStation(inorMcdonald);
			//생성된 스레드를 실행 시킵니다.
			tempThread.start();
			//생성된 스레드를 ArrayList에 추가 합니다.
			customers.add(tempThread);
		}


 for문 내부를 살펴 보겠습니다. Customer 객체 tempCustomer를 생성 했습니다. 그리고 Thread 객체를 하나 만드는데 생성자에 이전에 생성 했던 tempCustomer 객체를 매개 변수로 넘겨줬습니다. 이렇게 하나의 스레드를 만들었습니다. 그리고 tempCustomer 객체를 이용해서 실행 하는 것이 아니라 tempThread 객체를 이용해서 스레드를 실행 시켰습니다. 위 코드의 실행 결과는 Thread로 구현한 예제와 비슷 합니다. 아래는 실행 결과 입니다.



Comments