장점
단점
package test.thread1;
public class ThreadA /*extends Thread*/ implements Runnable {
@Override
public void run() {
// 다른 스레드 클래스와 동시 처리하고 싶은 내용을 코드로 작성함
// 다른 스레드가 동작하지 않는 구간에서 이 부분 처리함. 그냥 보기에는 동시에 처리되는 것처럼 보일 수 있음.
for(int i = 1; i <= 10; i++) {
System.out.println("★");
try {
Thread.sleep(100); // sleep을 안 써주면 A 동작 다한 후 B 동작함.
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package test.thread1;
public class ThreadB /*extends Thread*/ implements Runnable {
@Override
public void run() {
for(int i = 1; i <= 10; i++) {
System.out.println(i);
try {
Thread.sleep(100); // sleep을 안 써주면 A 동작 다한 후 B 동작함.
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package test.thread1;
public class ThreadC extends Thread {
@Override
public void run() {
super.run();
for(int i = 1; i <= 10; i++) {
System.out.println("♥");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package test.thread1;
public class TestThread {
public static void main(String[] args) {
// Runnable 인터페이스 상속 시
// 1. 스레드 생성
Thread t1 = new Thread(new ThreadA());
Thread t2 = new Thread(new ThreadB());
// Thread extends 시
ThreadC t3 = new ThreadC();
// 1-2. 우선순위 설정
t2.setPriority(Thread.MAX_PRIORITY);
// 2-1. t1 스레드 start(); --> 실행(run()) 대기
t1.start();
// 2-2. t2 스레드 start(); --> 실행(run()) 대기
t2.start();
t3.start();
}
}
// 실행결과
1
♥
★
2
♥
★
3
★
♥
4
♥
★
★
♥
5
♥
6
★
7
♥
★
8
★
♥
9
♥
★
10
★
♥
우선 순위 방식(Priority)
순환 할당 방식(Round-Robbin)
📌 sleep() - 일시 정지
💡 sleep(long millis) - ms만큼 일시 정지
sleep(long millis, int nanos) - ms + nanos만큼 일시 정지
지정된 시간동안 스레드를 멈추게하여 일시 정지상태가 된다.
지정된 시간이 다 되거나 interrupt()가 호출되면 InterruptedException이 발생되어 실행 대기 상태가 되기 때문에 항상 예외 처리(try - catch)를 해주어야 한다.
📌 interrupt() - 작업 취소
💡 void interrupt() - interrupted 상태를 true로 변경
boolean isInterrupted() - interrupted상태를 반환
static boolean interrupted() - interrupted상태를 반환하고 false로 변경
진행 중인 스레드의 작업이 끝나기 전에 취소시킨다.
interrupt() 메소드는 스레드의 작업을 일시정지시키며 종료시키지는 않는다.
Thread 객체의 interrupted상태를 변경시킨다.
📌 suspend(), resume(), stop() - 실행 제어
💡 suspend() - 스레드 일시 정지
resume() - suspend()로 일시 정지된 스레드를 실행 대기 상태로 변경
stop() - 스레드 종료
세 가지 메소드 모두 교착상태를 일으키기 쉬워 사용이 권장되지 않는다.
📌 yield() - 작업 양보
💡 yield() - 작업 시간 양보
스레드가 자신에게 주어진 작업 시간을 다음 차례의 스레드에게 양보한다.
yield() 메소드를 수행하면 실행 대기 상태가 된다.
프로그램의 응답성을 높이고 효율적인 실행을 위해 사용한다.
📌 join() - 다른 스레드의 종료 기다림
💡 join() - 다른 스레드의 작업을 마칠 때까지 일시 정지
join(long millis) - 다른 스레드의 작업 종료 또는 ms 만큼 일시 정지
join(long millis, int nanos) - 다른 스레드의 작업 종료 또는 ms+nanos만큼 일시정지
스레드가 작업을 잠시 멈추고 다른 스레드의 작업이 수행하도록 할 때 사용한다.
interrupt()에 의해 대기 상태에서 벗어날 수 있고 InterruptException이 발생하므로 예외 처리(try - catch)를 해줘야 한다.
일반 메소드는 스레드1, 2 동시에 공유 가능하다.
하지만 동기화는 스레드1이 끝나야 스레드2가 실행이 가능하다.
// 동기화 메소드
public synchronized void method() {
// 한 개의 스레드만 실행할 수 있음.
}
// 동기화 블록
public void method1() {
// 여러 스레드 실행할 수 있음
synchronized (공유객체) {
// 한 개의 스레드만 실행할 수 있음.
}
// 여러 스레드 실행할 수 있음
}
📌 wait() - 스레드 대기
💡 void wait() - 락을 반납하고 통지를 대기
void wait(long millis) - 락을 반납하고 ms만큼 대기
void wait(long millis, int nanos) - 락을 반납하고 ms+nanos만큼 대기
동기화된 블록 안에서 다른 스레드가 이 객체의 notify(), notifyAll()을 호출하거나 지정된 시간이 지날 때까지 현재의 스레드를 대기시킨다.
📌 notify() - 스레드를 깨움
💡 void notify() - 객체 대기 풀의 임의의 스레드에 통지
동기화된 블록 안에서 호출한 객체 내부에 대기중인 스레드를 깨운다.
여러 스레드가 있을 경우 임의의 스레드 하나에만 통보
📌 notifyAll() - 모든 스레드를 깨움
💡 void notifyAll() - 객체 대기 풀의 모든 스레드에 통지
동기화된 블록 안에서 호출한 객체 내부에 대기중인 모든 스레드를 깨운다.
하지만, lock은 하나의 스레드만 얻을 수 있다.