위 사진에서 게임 진행과 별개로 시간이 자동적으로 흐르는 것을 볼 수 있다.
현재 시간 : 7시
이는 멀티쓰레드를 이용하여 구현한 것으로 쓰레드의 개념과 구현 방법에 대해 정리해보고자 한다.
스레드(Thread)란?
프로세스는 프로그램을 수행하는 데 필요한 데이터와 메모리 등의 자원 그리고 쓰레드로 구성되어 있다. 이때 프로세스의 자원을 이용해 실제로 작업을 수행하는 것이 바로 쓰레드 이다.
모든 프로세스에는 최소한 하나 이상의 쓰레드가 존재하며, 둘 이상의 쓰레드가 존재하는 것을 '멀티쓰레드(multi-thread)라고 한다.
하나의 프로세스가 가질 수 있는 쓰레드의 개수는 제한되어 있지 않으나 쓰레드가 작업을 수행하는데 개별적인 메모리 공간(호출스택)을 필요로 하기 때문에 프로세스의 메모리에 따라 생성할 수 있는 쓰레드의 수가 결정된다.
CPU의 코어가 한 번에 단 하나의 작업만 수행할 수 있어 실제로 동시에 처리되는 작업의 개수는 코어의 개수와 일치한다. 그러나 멀티쓰레드는 각 코어가 아주 짧은 시간 동안 여러 작업을 번갈아 가며 수행하게 함으로써 여러 작업들이 모두 동시에 수행되는 것 처럼 보이게 한다.
멀티쓰레딩의 장단점
장점 | 단점 |
- CPU의 사용률을 향상 - 자원을 보다 효율적으로 사용 가능 - 사용자에 대한 응답성이 향상 - 작업이 분리되어 코드가 간결 |
- 동기화 : 한 스레드가 진행중인 작업을 다른 스레드가 간섭하지 못하도록 막는 것 - 교착상태 : 두 스레드가 자원을 점유한 상태에서 서로 상대편이 점유한 자원을 사용하려고 기다리느라 진행이 멈춰있는 상태 |
쓰레드 구현 방법
1. Thread 클래스 상속
- 다른 클래스를 상속받을 수 없는 단점 존재
class ThreadEx extends Thread {
@Override
public void run() { /* 작업 내용 */}
}
2. Runnable 인터페이스 구현
- 재사용성이 높고 코드의 일관성을 유지하므로 보다 객체지향적인 방법
class ThreadIn implements Runnable {
public void run() { /* 작업 내용 */}
}
Thread클래스 상속 vs Runnable 인터페이스 구현
1. 인스턴스 생성 방법
// 상속 thread
ThreadEx t1 = new ThreadEx(); // Thread의 자손클래스의 인스턴스 생성
// 인터페이스 thread
Runnable r = new ThreadIn(); // Runnable을 구현한 클래스의 인스턴스 생성
Thread t2 = new Thread(r); // 생성자 Thread
// 위를 한줄로 간단히
Thread t2 = new Thread(new ThreadIn());
Runnable 인터페이스를 구현한 경우, Runnable 인터페이스를 구현한 클래스의 인스턴스를 생성한 다음, 이 인스턴스를 Thread 클래스 생성자의 매개변수로 제공해야 한다.
2. Thread 클래스의 메서드 호출(getName())
class ThreadEx extends Thread {
@Override
public void run() {
// 조상인 Thread의 getName() 호출
System.out.println(getName());
}
}
class ThreadIn implements Runnable {
public void run() {
// Thread.currentThread() - 현재 실행중인 Thread 반환
System.out.println(Thread.curreuntThread().getName());
}
}
- Thread클래스 상속 : 자손 클래스에서 조상인 Thread 클래스의 메서드를 직접 호출 가능
- Runnable 구현 : Thread 클래스의 static 메서드인 currentThread()를 호출하여 쓰레드에 대한 참조를 얻어와야만 호출 가능
쓰레드의 실행 - start()
t1.start();
t2.start();
쓰레드는 자동으로 실행되지 않고 start()를 호출해야만 실행된다. 하지만 start()가 호출되었다고 해서 바로 실행되는 것이 아니라, 일단 실행 대기 상태가 되어 자신의 차례가 되었을때 실행된다. 물론 실행대기중인 쓰레드가 하나도 없으면 곧바로 실행이 된다. 쓰레드의 실행 순서는 OS의 스케줄러가 작성한 스케줄에 따라 결정된다.
하나의 쓰레드에 대해 한번의 start()만 호출이 될 수 있으므로, 한번 실행이 종료된 쓰레드는 다시 실행할 수 없다. 만일 쓰레드의 작업을 한번 더 실행해야 한다면 새로운 쓰레드를 생성한 다음 start()를 호출해야한다.
ThreadEx t1 = new ThreadEx();
t1.start();
t1 = new ThreadEx(); // 다시 생성
t1.start();
나는 어떤 방식을 사용했나?
나의 경우 Thread 클래스를 상속 받은 Time 클래스를 생성했다. 그리고 그 안에서 생성자를 만들고, run()메서드를 오버라이드 해주었다.
Runnable 인터페이스를 사용하지 않은 이유는 해당 Time 쓰레드의 경우 다른 클래스를 상속 받지 않기때문에 인스턴스를 생성하고 Thread 클래스의 메서드를 좀더 간결히 사용할 수 있는 상속의 방식을 택했다.
Main에서 Time 스레드를 위와 같이 인스턴스를 생성하고 구현을 해주었다.
자료 출처
Java의 정석 - 남궁 성 지음
'JAVA' 카테고리의 다른 글
[JAVA] 쓰레드 우선 순위 설정 (0) | 2023.07.19 |
---|---|
[JAVA] 콘솔 입력 방법 (Scanner, InputStream, InputStreamReader, BufferedReader) (0) | 2023.07.13 |
[JAVA] 간단한 콘솔게임 만들기 (기획) (0) | 2023.07.13 |
댓글