이번 포스팅에서는 자바에서 스레드를 이용해 멀티쓰레딩을 구현하는 방법을 알아보려고 한다.
자바에서 스레드를 생성하는 방법은 두 가지가 있다.
1. Thread 상속
class Task1 extends Thread {
@Override
public void run() { // 이부분은 이대로 사용해줘야함
System.out.println("task1 started \n");
for (int i = 101; i <= 199; i++) {
System.out.print(i +" ");
}
// 스레드를 1초동안 대기
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// 스케쥴러에 대한 힌트로
// thread가 cpu를 사용가능한 이 상태를 양보하겠다는 뜻
// 이것도 강제되는 것이 아니고 스케줄러가 이를 무시할 수 있음
Thread.yield();
// synchronized(동기화)
// 특정한 시점에 하나의 thread만 동기화된 메서드들을 사용할 수 있음
// 동기화된 모든 메서드들을 특정 시점에는 하나의 스레드만이 사용 가능하고
// 다른 스레드들은 해당 스레드의 작업이 끝날때까지 대기해야하므로
// 오버헤드가 발생
System.out.println("\n task1 done");
}
}
class Task2 implements Runnable {
@Override
public void run() {
System.out.println("task2 started \n");
for (int i = 201; i <= 299; i++) {
System.out.print(i +" ");
}
System.out.println("\n task2 done");
}
}
스레드를 1초동안 대기시킴
예외가 발생할 수 있으므로 try-catch로 감싸주자
스케줄러에게 보내는 힌트로 스레드가 cpu를 활용할 수 있는 권한을 양도한다는 뜻이다.
다만, 강제되는 것이 아니기 때문에 스케줄러가 이를 무시할 수 있다.
먼저 자료구조 중에 HashTable을 확인해보자

HashTable 클래스를 확인해보면 synchronized라는 키워드가 여러 메서드에 붙어있는 것을 알 수 있는데, 이는 동기화를 뜻한다.
멀티스레드 환경에서 어떤 하나의 메서드가 해당 객체에서 synchronized키워드가 붙은 메서드를 사용하고 있다면, 다른 스레드는 선점하고 있는 스레드의 작업이 완료될 때까지 synchronized키워드가 붙은 어떤 메서드도 사용하지 못한다.
해당 작업이 완료될 때까지 대기해야 하기 때문에 오버헤드가 발생한다.
객체 생성 등을 통해 스레드를 초기화한 상태
start()가 호출 시
실행 예정이지만 다른 스레드 실행 등의 이유로 실행되지는 준비하고 있는 상태
현재 실행중인 상태
스레드의 실행이 완료되거나, stop() 메서드가 호출되어 스레드가 종료되었을 때의 상태
class Task1 extends Thread {
@Override
public void run() { // 이부분은 이대로 사용해줘야함
System.out.println("task1 started \n");
for (int i = 101; i <= 199; i++) {
System.out.print(i +" ");
}
// 스레드를 1초동안 멈춤
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Thread.yield();
System.out.println("\n task1 done");
}
}
class Task2 implements Runnable {
@Override
public void run() {
System.out.println("task2 started \n");
for (int i = 201; i <= 299; i++) {
System.out.print(i +" ");
}
System.out.println("\n task2 done");
}
}
public class ThreadBasicsRunner {
public static void main(String[] args) throws InterruptedException {
// task1
System.out.print("task1 kicked off \n");
Task1 task1 = new Task1();
task1.run(); // 이렇게 사용하면 이 메서드가 끝난 다음에 다음 코드가 실행이 됨
task1.setPriority(1);
task1.start(); // 이렇게 하면 병렬처리가 됨
// task2
// Runnable을 이용한 멀티쓰레딩
System.out.print("task2 kicked off \n");
Task2 task2 = new Task2();
Thread task2Thread = new Thread(task2);
task2Thread.setPriority(10);
task2Thread.start();
//task1이 완료될 때까지 기다리기
task1.join();
task2Thread.join();
// task1,2가 완료가 되어야만 다음 로직이 실행이 됨
// task3
System.out.print("task3 kicked off \n");
for (int i = 301; i <= 399; i++) {
System.out.print(i +" ");
}
System.out.println("\n task3 done");
System.out.println("main done");
}
}
task1.setPriority(1);
스레드의 우선순위 부여하는 메서드이다.
최소 우선순위 1
보통 우선순위 5
최고 우선순위 10
다만, 무조건적으로 우선순위가 정해지는 것이 아니라 권장? 추천?정도의 뜻으로 반드시 이 우선순위가 지켜지는 것은 아니다.
start()
새로운 스레드가 생성되며 스레드가 실행되면 run메서드를 실행시킨다.
동일한 객체에서 두번 이상 호출 시 IllegalThreadStateException이 발생한다.

멀티스레드로 동작한다.
run()
task1.join();
: task1 스레드의 실행이 완료될 때까지 기다린다.
위에서 작성했던 코드의 일부를 보자
//task1이 완료될 때까지 기다리기
task1.join();
task2Thread.join();
// task1,2가 완료가 되어야만 다음 로직이 실행이 됨
// task3
System.out.print("task3 kicked off \n");
for (int i = 301; i <= 399; i++) {
System.out.print(i +" ");
}
System.out.println("\n task3 done");
System.out.println("main done");
