일단 둘의 공통점은 스레드에 이름을 따로 붙이지 않았다면 Thread-0, Thread-1... 이렇게 붙는다.
그리고 각각 독립적인 영역을 갖고 Thread를 사용할 때는 log를 사용하는 게 좋다.
그래야지 언제 실행됐는지 알 수 있다.
마지막으로 스레드 실행 순서가 보장되지 않는다.
코드를 먼저 썼다고 해서 먼저 나오지 않는다. 어느 게 먼저 실행될 지는 설정해 줄 수 있지만, 그것도 그 스레드가 높은 확률로 먼저 실행된다는 것이지 확실하게 먼저 실행시켜준다는 건 아니다.
현재 스레드에 접근하고 싶으면 currentThread(), 거기다가 이름까지 불러오고 싶으면은 getName()을 사용하면 된다.
클래스에 extends Thread를 붙여 스레드로 만들어 준다.
다른 객체들처럼 객체를 만들어 사용하면 된다. 다만, 메서드를 직접 호출하는 것이 아닌 start()로 메서드로 실행해야 된다.
안 그러면 main에서 일반 메서드처럼 실행시켜 버린다.
반드시 start()로 실행해야지 Thread로 독립적인 영역을 갖게 된다.
클래스에 implements Runnable를 붙여 구현시킨다.
사용할 떄는 객체를 생성하고 또다시 Thread 스레드 이름 = new Thread(객체 이름)으로 따로 스레드를 만들어 사용한다.
이것은 번거로울 수 있으나 장점이기도 하다. Thread를 상속받을 때 생기는 불필요한 Thread 속 다른 메서드를 사용하지 않게 되기 때문이다. 더 유연하게 사용할 수 있다.
실행시킬 때는 똑같이 start()로 실행하면 된다.
1. 중첩 정적 클래스
Runnable 클래스를 한 개의 클래스에서만 사용할 것 같으면 그 안에다가 내부 정적 클래스로 생성해도 된다.
public class OuterClassStatic {
private String outerMessage = "안녕하세요, 바깥 클래스입니다.";
// 정적 중첩 클래스
static class StaticNestedRunnable implements Runnable {
private String taskName;
public StaticNestedRunnable(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
// 정적 중첩 클래스는 바깥 클래스의 non-static 멤버에 직접 접근할 수 없습니다.
// System.out.println(outerMessage); // 컴파일 에러 발생
System.out.println(Thread.currentThread().getName() + ": " + taskName + " 실행 중 (정적 중첩 클래스)");
}
}
public static void main(String[] args) {
// 정적 중첩 클래스는 바깥 클래스 객체 생성 없이 바로 생성 가능
StaticNestedRunnable runnable1 = new StaticNestedRunnable("작업 A");
Thread thread1 = new Thread(runnable1);
thread1.start();
StaticNestedRunnable runnable2 = new StaticNestedRunnable("작업 B");
Thread thread2 = new Thread(runnable2);
thread2.start();
}
}
일단 결론부터 말하자면 대부분 Runnable를 사용한다.
왜냐하면 Runnable이 좀더 유연하고 쓰기 편하다. 자바에서는 다중 상속은 안 되지만 다중 구현은 가능하기 때문이다.
예를 들어 이미 무언가를 상속받은 클래스에서는 Thread 상속을 사용하지 못하는 것이다.
게다가 Runnable을 사용할 경우 Thread와 따로 관리할 수 있게 된다.
하나의 Runnable 클래스로 여러 개의 스레드를 생성할 수 있는 건 덤이고.