Thread Object 관리 - #3

김병우·2024년 3월 11일
0

Java-Thread

목록 보기
3/5

전편의 Runnable Interface를 이용한 Thread를 구현의 뒷편입니다.
제가 실습한 코드는 혹시 몰라 올려둡니다. https://github.com/helloJosh/nhn-homework-thread-study

1. Thread object 관리

Runnable interface를 이용할 경우 별도의 Thread object 관리가 필요합니다.

  1. 생성 후 자동 종료될때 자동 삭제한다.
  2. 구현되는 Class 내에 Thread obejct를 포함시켜 관리한다.
  3. 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로 구현 가능하다.
  • 각각의 장,단점이 있기 때문에 필요할때 사용하면 될 것 같다.
profile
백엔드개발자

0개의 댓글