본문 바로가기

배운내용 정리

Java Thread(2)

1. Thread 와 Runnable

2. 데몬 쓰레드와 사용자 쓰레드

 

 

1. Thread 와 Runnable

Java에서 쓰레드를 구현하고 실행하는 방법에 대해서  학습한다.

Java에서 제공하는 Thread 클래스를 상속받아 쓰레드를 구현한다.

public class TestThread extends Thread {
				@Override
				public void run() {
							// 쓰레드 수행작업
				}
}

...

TestThread thread = new TestThread(); // 쓰레드 생성
thread.start() // 쓰레드 실행
  • 여기서 핵심은 run() 메서드 이다.
  • run() 메서드에 작성된 코드가 쓰레드가 수행할 작업이다.

1. Thread

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

class TestThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i <100; i++) {
            System.out.print("*");
        }
    }
}

2. Runnable

public class TestRunnable implements Runnable {
				@Override
				public void run() {
							// 쓰레드 수행작업 
				}
}

...

Runnable run = new TestRunnable();
Thread thread = new Thread(run); // 쓰레드 생성

thread.start(); // 쓰레드 실행
  • 여기서의 run() 메서드도 마찬가지로 쓰레드가 수행할 작업이다.
  • 그렇다면 Thread를 직접 상속받아 사용하는 방법이 더 간단해 보이는데 왜? Runnable을 사용하여 쓰레드를 구현하는 방법을 소개해드렸을까요?
  • 바로 클래스와 인터페이스 차이 때문입니다. Java는 다중 상속을 지원하지 않는다.
  • 그렇기 때문에 Thread를 상속 받아 처리하는 방법은 확장성이 매우 떨어진다.
  • 반대로 Runnable은 인터페이스이기 때문에 다른 필요한 클래스를 상속 받을 수 있다.
    • 따라서 확정성에 매우 유리하다.
public class Main {
    public static void main(String[] args) {

        Runnable run = new TestRunnable();
        Thread thread = new Thread(run);

        thread.start();
    }
}

class TestRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i <100; i++) {
            System.out.print("$");
        }
    }
}

3. 람다식

public class Main {
    public static void main(String[] args) {
        Runnable task = () -> {
            int sum = 0;
            for (int i = 0; i < 50; i++) {
                sum += i;
                System.out.println(sum);
            }
            System.out.println(Thread.currentThread().getName() + " 최종 합 : " + sum);
        };

        Thread thread1 = new Thread(task);
        thread1.setName("thread1");
        Thread thread2 = new Thread(task);
        thread2.setName("thread2");

        thread1.start();
        thread2.start();
    }
}
  • run() 메서드에 작성했던 쓰레드가 수행할 작업을 실행 블록 { } 안에 작성하시면 된다.
  • setName() 메서드는 쓰레드에 이름을 부여할 수 있다.
  • Thread.currentThread().getName() 은 현재 실행 중인 쓰레드의 이름을 반환. 

싱글 쓰레드

public class Main {
    public static void main(String[] args) {
        Runnable task = () -> {
            for (int i = 0; i < 100; i++) {
                System.out.print("$");
            }
        };


        Thread thread1 = new Thread(task);
        thread1.setName("thread1");

        thread1.start();
    }
}
  • 메인 쓰레드에서 싱글 쓰레드로 하나의 작업을 실행.
  • $ 표시가 순서대로 출력되는 모습을 볼 수 있다.

멀티 쓰레드

public class Main {
    public static void main(String[] args) {
        Runnable task = () -> {
            for (int i = 0; i < 100; i++) {
                System.out.print("$");
            }
        };
        Runnable task2 = () -> {
            for (int i = 0; i < 100; i++) {
                System.out.print("*");
            }
        };


        Thread thread1 = new Thread(task);
        thread1.setName("thread1");
        Thread thread2 = new Thread(task2);
        thread2.setName("thread2");

        thread1.start();
        thread2.start();
    }
}
  • 메인 쓰레드에서 멀티 쓰레드로 여러개의 작업을 실행 한다.
  • $ 와 * 이 순서가 일정하지 않게 출력되는 모습을 볼 수 있다.
  • 여러번 실행해서 보면 순서가 정해져 있지 않아 출력의 형태가 계속해서 변화하는 것을 확인할 수 있다.
    • 즉, 2개의 쓰레드는 서로 번갈아가면서 수행된다.
  • 여기서 이 두 쓰레드의 실행 순서나 걸리는 시간은 OS의 스케줄러가 처리하기 때문에 알 수 없다.

4. 데몬 쓰레드와 사용자 쓰레드

1. 데몬 쓰레드

public class Main {
    public static void main(String[] args) {
        Runnable demon = () -> {
            for (int i = 0; i < 1000000; i++) {
                System.out.println("demon");
            }
        };

        Thread thread = new Thread(demon);
        thread.setDaemon(true); // true로 설정시 데몬스레드로 실행됨

        thread.start();

        for (int i = 0; i < 100; i++) {
            System.out.println("task");
        }
    }
}

demon 쓰레드는 우선순위가 낮고 다른 쓰레드가 모두 종료되면 강제 종료 당하기 때문에 main() 쓰레드의 task가 100번이 먼저 찍히면 종료되어 1000000번 수행이 되지 않고 종료된다.

 

2. 사용자 쓰레드

  • 보이는 곳(foregorund) 에서 실행되는 높은 우선순위를 가진 쓰레드를 말한다.
  • 프로그램 기능을 담당하며 대표적인 사용자 쓰레드로는 메인 쓰레드가 있다.
  • 사용자 쓰레드 만드는법 : 기존에 만들었던 쓰레드들이 다 사용자 쓰레드 이다.

'배운내용 정리' 카테고리의 다른 글

Spring port error  (1) 2023.10.31
Java Thread(3)  (0) 2023.10.30
Java Thread(1)  (0) 2023.10.24
Java Generic  (1) 2023.10.23
Java 예외처리  (1) 2023.10.23