public class HelloThread extends Thread{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " : run()");
}
}
// ...
public class HelloThreadMain {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + ": main() start");
HelloThread helloThread = new HelloThread();
System.out.println(Thread.currentThread().getName() + ": start() 호출 전");
helloThread.start();
System.out.println(Thread.currentThread().getName() + ": start() 호출 후");
System.out.println(Thread.currentThread().getName() + ": main() end");
}
}
// 실행 결과
main: main() start
main: start() 호출 전
main: start() 호출 후
Thread-0: run()
main: main() end
위 코드의 실행 결과를 보게 되면 스레드 생성 전후 메모리 변화가 아래와 같이 일어나는 것을 확인할 수 있다.
스레드 간의 실행 순서는 얼마든지 달라질 수 있다.
CPU 코어가 2개여서 물리적으로 정말 동시에 실행될 수 있고, 하나의 CPU 코어에서 시간을 나누어 실행될 수도 있다.
그리고 한 스레드가 얼마나 오랜기간 실행되는지도 보장하지 않는다. 한 스레드가 먼저 다 수행한 후 다른 스레드가 수행될 수도 있고, 둘이 번갈아 가면서 수행할 수도 있다.
스레드는 순서와 실행 기간을 모두 보장하지 않는다.
스레드 순서와 실행 기간은 운영체제가 결정하는 것이지, 애플리케이션 코드에서 결정하는 것이 아니다.
스레드는 사용자 스레드와 데몬 스레드 2 종류로 구분할 수 있다.
public class DaemonThreadMain {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + " : main() start");
DaeminThread daeminThread = new DaeminThread();
daeminThread.setDaemon(true);
daeminThread.start();
System.out.println(Thread.currentThread().getName() + " : main() end");
}
static class DaeminThread extends Thread {
@Override
public void run(){
System.out.println(Thread.currentThread().getName() + " : run()");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + " : end()");
}
}
}
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) {
System.out.println(Thread.currentThread().getName() + " : main() start");
HelloRunnable runnable = new HelloRunnable();
Thread thread = new Thread(runnable);
thread.start();
System.out.println(Thread.currentThread().getName() + " : main() end");
}
}
// 실행 결과
main: main() start
main: main() end
Thread-0: run()
import static util.MyLogger.log;
public class InnerRunnableMainV1 {
public static void main(String[] args) {
log("main() start");
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
log("main() end");
}
static class MyRunnable implements Runnable {
@Override
public void run() {
log("run()");
}
}
}
import static util.MyLogger.log;
public class InnerRunnableMainV2 {
public static void main(String[] args) {
log("main() start");
Runnable runnable = new Runnable() {
@Override
public void run() {
log("run()");
}
};
Thread thread = new Thread(runnable);
thread.start();
log("main() end");
}
}
import static util.MyLogger.log;
public class InnerRunnableMainV3 {
public static void main(String[] args) {
log("main() start");
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
log("run()");
}
});
thread.start();
log("main() end");
}
}
import static util.MyLogger.log;
public class InnerRunnableMainV4 {
public static void main(String[] args) {
log("main() start");
Thread thread = new Thread(() -> log("run()"));
thread.start();
log("main() end");
}
}