스레드의 생성
Runnable 인터페이스 구현을 사용하자
- Thread 클래스 상속
- Runnable 인터페이스 구현
스레드는 Thread 클래스를 상속해서 만들거나, Runnable 인터페이스를 구현하는 방법으로 생성할 수 있다.
실무에서는 Runnable 인터페이스를 구현하는 방법을 선호한다.
Thread 클래스를 상속하는 경우, 다른 상속이 있는 경우에는 사용할 수 없다( 다중 상속 X )
따라서, 스레드와 실행할 작업을 명확히 나누어서 개발할 수 있는 Runnable 방식을 사용한다.
스레드 생성 - Thread 클래스 상속
Thread 클래스 상속 후 run() 메소드를 오버라이딩한다.
public class HelloThread extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " : run()");
}
}
객체 생성 후 start() 메소드를 사용하여 실행한다.
public class HelloThreadMain {
public static void main(String[] args) {
HelloThread helloThread = new HelloThread();
helloThread.start();
}
}
스레드 생성 - Runnable 인터페이스 구현
Runnable 인터페이스를 구현하는 클래스를 만들고, Thread 객체를 생성할때 생성자로 넣어준다.
public class HelloRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ": run()");
}
}
public class HelloRunnableMain {
public static void main(String[] args) {
HelloRunnable runnable = new HelloRunnable();
Thread thread = new Thread(runnable);
thread.start();
}
}
Runnable을 이용하여 다양한 방법으로 스레드를 생성할 수 있다.
가장 기본적으로, Runnable 인터페이스를 구현하고 이를 스레드 생성 시 파라미터로 넣어준다.
<기본>
public class InnerRunnableMainV1 {
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
}
static class MyRunnable implements Runnable {
@Override
public void run() {
log("run()");
}
}
}
다음과 같이 익명클래스를 사용하여 만들 수 있고, 이는 람다로 간단하게 표현할 수 있다.
익명클래스를 사용하는 경우는, 재사용없이 간단히 표현해줄때 사용하면 효과적일 수 있다.
( 재사용이 많은 경우에는, 따로 선언해놓는 방법이 효율적이다. )
<익명클래스>
public class InnerRunnableMainV2 {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
log("run()");
}
});
thread.start();
}
}
<람다 표현식>
public class InnerRunnableMainV2 {
public static void main(String[] args) {
Thread thread = new Thread(() -> log("run()"));
thread.start();
}
}
결국 람다를 사용한 이 방식을 자주 사용한다.
람다의 경우 다음번에 정리하는 시간을 가져야겠다.( 2024년 8월 19일 기준! )
Runnable의 경우, 한번 만들어둔 것을 반복해서 호출 할 수 있다.
맨 위에 예시 HelloRunnable을 가져와서 반복 생성해보자.
public class ManyThreadMainV1 {
public static void main(String[] args) {
HelloRunnable runnable = new HelloRunnable();
Thread thread1 = new Thread(runnable);
thread1.start();
Thread thread2 = new Thread(runnable);
thread2.start();
Thread thread3 = new Thread(runnable);
thread3.start();
}
}
스레드의 실행
start() 메소드 호출( run() 메소드 호출 x )
만들어둔 스레드 객체를 생성하고, start() 메소드를 실행한다
run() 메소드가 아닌, start() 메소드를 호출해줘야 한다.
( start()를 호출해야, 별도 스레드에서 run()을 호출해줌 )
run() 메소드를 호출하는 경우, 별도의 스레드가 생성되면서 그 스레드가 run()을 호출하는 것이 아닌,
현재 스레드가 단순히 run() 메소드를 실행하게 된다.
( 스레드를 생성해서 그 스레드가 run()을 실행하려고 했던 원래 의도에서 벗어남 )
스레드 메소드
currentThread() - 해당 코드를 실행하는 스레드의 정보 조회
currentThread().getName() - 실행중인 스레드의 이름 조회
( 별도의 이름을 입력해주지 않으면, thread-0, thread-1 등으로 임의 생성된다 )
데몬 스레드
백그라운드에서 보조 작업을 수행하는 스레드
스레드는 사용자 스레드와 데몬 스레드로 구분할 수 있다
( Thread 메소드 setDaemon()을 true로 하면 데몬스레드, 디폴트는 false )
모든 유저 스레드가 종료되면, 데몬 스레드는 자동으로 종료된다.
로거
스레드를 실행할때는 로그를 남기는 것 이 중요하다.
( 어떤 스레드가 실행되었는지를 알아야 하기 때문에 )
로그를 남기는 메소드를 따로 구성하자!
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public abstract class MyLogger {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss.SSS");
public static void log(Object obj) {
String time = LocalTime.now().format(formatter);
System.out.printf("%s [%9s] %s\n", time, Thread.currentThread().getName(), obj);
}
}
'Java > 김영한의 실전자바' 카테고리의 다른 글
스레드 - join() (0) | 2024.08.26 |
---|---|
스레드 제어 (0) | 2024.08.22 |
프로세스와 스레드 (0) | 2024.08.13 |
[김영한의 실전 자바 - 기본편] 기본형과 참조형 (0) | 2024.01.21 |
[김영한의 실전 자바 - 기본편] 클래스 (0) | 2024.01.13 |