전편의 Runnable Interface를 이용한 Thread를 구현의 뒷편입니다.
제가 실습한 코드는 혹시 몰라 올려둡니다. https://github.com/helloJosh/nhn-homework-thread-study
1. Thread object 관리
Runnable interface를 이용할 경우 별도의 Thread object 관리가 필요합니다.
- 생성 후 자동 종료될때 자동 삭제한다.
- 구현되는 Class 내에 Thread obejct를 포함시켜 관리한다.
- Thread Pool을 이용한다.
2. 생성 후 종료 자동 삭제
public class RunnableThreadCounter implements Runnable{
String name;
int count;
int maxCount;
public RunnableThreadCounter(String name, int maxCount){
// 중략
}
// Gett 중략
@Override
public void run(){
while(count < maxCount){
try{
Thread.sleep(1000);
count++;
System.out.println(name +":"+count);
} catch (InterruptedException e) {
System.out.println(name+": interrupted");
Thread.currentThread().interrupt();
}
}
}
public static void main(String[] args) {
RunnableCounter counter = new RunnableCounter("counter", 5);
Thread thread = new Thread(counter);
thread.start();
}
}
- 간편하지만 몇가지 문제점이 있다.
- Counter와 Thread의 연결관계의 모호함
- 특정 Instance가 동작중을 확인하거나 멈추기엔 힘든코드이다.
3.Class내에서 Thread를 field로 포함
public class RunnableThreadCounter implements Runnable{
String name;
int count;
int maxCount;
Thread thread;
public RunnableThreadCounter(String name, int maxCount){
this.name = name;
this.maxCount = maxCount;
count =0;
thread = new Thread(this);
}
public void start(){
thread.start();
}
public void stop(){
//thread.currentThread().interrupt();
thread.interrupt();
}
public Thread getThread(){
return this.thread;
}
// Getter 중략
@Override
public void run(){
while(!Thread.currentThread().isInterrupted() && count < maxCount){
try{
Thread.sleep(1000);
count++;
System.out.println(name +":"+count);
} catch (InterruptedException e) {
System.out.println(name+": interrupted");
Thread.currentThread().interrupt();
}
}
}
public static void main(String[] args) {
RunnableThreadCounter[] counters = new RunnableThreadCounter[10];
Thread[] threads = new Thread[10];
LocalTime now = LocalTime.now();
boolean allStopped = false;
for(int i=0; i<counters.length ; i++){
counters[i] = new RunnableThreadCounter("counter "+(i+1), 10);
counters[i].getThread().start();
}
while(!allStopped){
if((counters[0].getCount()>5)){
for(int i=0;i<counters.length;i++){
counters[i].getThread().interrupt();
}
}
allStopped = true;
for(int i=0;i<counters.length;i++){
if(counters[i].getThread().isAlive()){
allStopped = false;
}
}
}
System.out.println("end :" + now);
}
}
- 이런식으로 Thread를 field로 추가함으로써 어떤 Counter, Thread에 연결짓거나 특정 지을 수 있다.
참고1
Thread.interrupt() , Thread.currentThread().interrupt()는 완전히 다른 코드이다.
Thread는 필드에 저장된 Thread를 의미하고 Thread.currentThread는 현재 돌고 있는 Thread를 의미한다. 즉 CurrentThread() 함수를 사용하면 Main Thread까지 튀어나오니 조심해야한다.
참고2
Thread 프로그래밍할때는 디버깅 모드가 제대로 작동하지 않아 Log나 콘솔에 직접 찍어줘야한다. 디버깅 모드로 실행시 원래 결과값과 다른 값이 나온다.
코드와는 다르게 생각해야하는 것 같다.
4. Thread Pool
ExecutorService를 이용해 thread pool을 생성한다. 이때, pool의 크기는 1로 한다.
ExecutorService pool = Executors.newFixedThreadPool(1);
Thread pool에 RunnableCounter instance를 생성해 넘기고 실행하도록 한다.
pool.execute(new RunnableCounter("counter1", 5));
pool.execute(new RunnableCounter("counter2", 5));
Thread pool을 종료하도록 명령을 내리고, 종료되길 기다린다.
pool.shutdown();
System.out.println("Shutdown called");
while (!pool.awaitTermination(2, TimeUnit.SECONDS)) {
System.out.println("Not yet finished");
}
System.out.println("All service finished");
5. Class 확장 vs Interface 구현 Thread
Class 확장Interface 구현
multiple inheritance을 지원하지 않으므로, 다른 class로부터의 추가적인 확장이 불가능하다. | Interface에 대한 multiple inheritance가 지원되고, 구현된 후에도 해당 class의 확장이 가능하다 |
Instance 생성 후 바로 실행할 수 있다. | Instance 생성 후 바로 사용할 수 없고, 추가적인 Thread object가 요구된다. |
간단한 class라도 별도의 class 정의가 필요하다. | Runnable interface는 functional interface로 Lambda로 구현 가능하다. |
- 각각의 장,단점이 있기 때문에 필요할때 사용하면 될 것 같다.
'Java > Thread' 카테고리의 다른 글
Synchronization Control - #5 (0) | 2024.07.27 |
---|---|
Thread Synchronization(쓰레드 동기화) - #4 (0) | 2024.07.27 |
Thread Counter 구현 - #2 (0) | 2024.07.27 |
Process(프로세스) vs Thread(쓰레드) - #1 (0) | 2024.07.27 |