
class MyThread extends Thread {
@Override
public void run () { // Thread 클래스의 run()을 오버라이딩
/* 작업 내용 */
}
}
MyTread t1 = new MyThread(); // 스레드 생성
t1.start();
Runnable 인터페이스를 구현한 경우는, 해당 클래스를 인스턴스화해서 Thread 생성자에 argument로 넘겨줘야 한다. 그리고 run()을 호출하면 Runnable 인터페이스에서 구현한 run()이 호출되므로 따로 오버라이딩하지 않아도 되는 장점이 있다.
class MyThread2 implements Runnable {
@Override
public void run () { // Runnable 인터페이스의 추상메서드 run()을 구현
/* 작업 내용 */
}
}
Runnable r = new MyThread2();
Thread t2 = new Thread(r); // Thread(Runnable r)
// Thread t2 = new Thread(new MyThread2 ());
t2.start();

main() 메서드 에서 start() 메서드가 실행되면 새로운 호출 스택을 생성하고, 새롭게 호출된 스택에서 run() 메서드를 실행시킨 뒤, start() 메서드는 종료한다. 스레드가 분리되며 각각의 호출 스택을 갖게 된다고 볼 수 있다.

1. NEW : 스레드가 생성되고 아직 start()가 호출되지 않은 상태
2. RUNNABLE : 실행 중 또는 실행 가능 상태
3. BLOCKED : 동기화 블럭에 의해 일시정지된 상태(lock이 풀릴 때까지 기다림)
4. WAITING, TIME_WAITING : 스레드의 작업이 종료되지는 않았지만 실행가능하지 않은(unrunnable) 일시정지 상태, TIME_WAITING은 일시정지시간이 지정된 경우를 의미
5. TERMINATED : 스레드 작업이 종료된 상태
static void sleep(long millis) // 천 분의 일 초 단위
static void sleep(long millis, int nanos) // 천 분의 일 초 + 나노 초
try {
Thread.sleep(1, 500000); // 스레드를 0.0015초 동안 멈추게 한다
} catch(InterruptedException e) {}
void delay(long millis) {
try {
Thread.sleep(millis);
} catch(InterruptedException e) {}
}
를 사용해서
delay(15);
식으로 사용할 수 있다. 이때 Thread.sleep을 사용하면 메인이 sleep 하는 것이고, th1.sleep 하면 th1 스레드가 sleep 하는 것을 의미해 보이지만 실제론 메인 스레드가 잠드는 것이다. 작성 방법상 에러가 발생하진 않지만 메인 스레드가 sleep 하는 목적으로 사용한다면(무엇보다 다른 스레드를 잠자게 하는 기능이 아니다) Thread.sleep() 으로 사용하도록 주의해야 한다.

class ThreadEx13_2 extends Thread {
public voide run ()
...
while(downloaded && !isInterrupted()){
// download 를 수행한다.
...
}
System.out.println("다운로드가 끝났습니다.");
}
}




1) 메서드 전체를 입계 영역으로 지정하고 싶은 경우 -- 반환 타입 앞에 syncronized
2) 특정 영역을 임계 영역으로 지정하고 싶은 경우 -- syncronized(객체의 참조 변수){}




/**
* 스레드 동기화 중 협력관계 처리작업 : wait() notify()
* 스레드 간 협력 작업 강화
*/
public synchronized void makeBread(){
if (breadCount >= 10){
try {
System.out.println("빵 생산 초과");
wait(); // Thread 를 waiting pool 로 이동 시킴
} catch (Exception e) {
}
}
breadCount++; // 초과하지 않으면 빵 생산
System.out.println("빵을 만듦. 총 " + breadCount + "개");
notify(); // waiting pool 에 쉬고 있던 Thread(eatBread) 를 깨움
}
public synchronized void eatBread(){
if (breadCount < 1){
try {
System.out.println("빵이 없어 기다림");
wait(); // 0보다 작으면 Thread 를 waiting pool 로 이동시킴
} catch (Exception e) {
}
}
breadCount--;
System.out.println("빵을 먹음. 총 " + breadCount + "개");
notify();
}
Q. 프로세스와 스레드의 기본적인 차이가 무엇인가요?
✅ 프로세스는 프로그램 코드, 메모리 및 할당된 리소스를 포함하는 실행 단위이며, 스레드는 동일한 메모리 공간과 리소스를 공유하는 프로세스 내에서 실행되는 가장 작은 실행 단위입니다. 프로세스 내에서 실제 작업을 수행하며, 모든 프로세스는 최소 하나의 스레드를 가지고 있습니다.
Q. 멀티 태스킹과 멀티 스레드의 차이점은 무엇인가요?
✅ 멀티태스킹은 여러 작업을 동시에 실행하는 것을 의미합니다. 다중 프로세싱에서는 각각 고유한 메모리 공간을 가진 여러 프로세스가 동시에 실행되지만, 멀티스레딩에서는 하나의 프로세스 내에서 여러 스레드가 실행되며, 동일한 메모리 공간을 공유합니다.
Q. 멀티 스레딩과 멀티 태스킹의 장단점은 무엇인가요?
✅ 멀티스레딩은 리소스를 효율적으로 활용하고, 응답성을 향상시키며, 코드 구조를 간소화하는 장점이 있습니다. 그러나 데드락과 같은 문제를 피하기 위해 동기화에 주의해야하며, 스레드 관리에서 복잡성이 대두될 수 있습니다.
Q. 자바에서 스레드는 어떻게 구현되며, Thread 클래스로 상속받거나 Runnable 인터페이스로 구현되는 차이점은 무엇인가요?
✅ 자바에서 스레드는 Thread 클래스를 확장하거나 Runnable 인터페이스를 구현함으로써 구현할 수 있습니다. Thread를 확장하는 것은 run() 메서드를 재정의해야 하지만, Runnable을 구현하는 것은 하위 클래스화가 필요하지 않으므로 관심사의 분리에 더 적합합니다.
Q. 스레드 실행 제어에서 interrupt() 메서드의 목적과 사용법을 설명해주세요.
✅ interrupt() 메서드는 대기 상태인 스레드의 상태를 대기에서 실행 가능한 상태로 변경하여 실행을 재개합니다. 스레드의 interrupted 상태를 true로 설정하며, isInterrupted() 또는 interrupted()를 사용하여 확인할 수 있는데, interrupted() 메서드는 현재 스레드의 interrupted 상태를 알려줌과 동시에 false 로 초기화시킵니다.
Q. suspend(), resume(), stop() 메서드를 사용할 때 주의할 점은 무엇인가요?
✅ 이러한 메서드들은 데드락 상황과 동기화 문제를 일으킬 가능성 때문에 사용이 중지되었습니다. 이러한 메서드들은 상태의 불일치와 예기치 않은 동작을 유발할 수 있으므로 사용을 지양해야 합니다.
Q. 동기화를 통해 공유 리소스에 대한 액세스를 관리하는 데 어떻게 도움이 되나요?
✅ 동기화는 하나의 스레드만이 한 번에 임계 구역에 액세스할 수 있도록 보장하여 공유 리소스의 동시 액세스를 방지하고 데이터 무결성을 유지합니다.
Q. 동기화에서 wait(), notify(), notifyAll() 메서드의 목적과 사용법을 설명해주세요.
✅ 이러한 메서드들은 스레드 간의 대기 및 알림 메커니즘을 관리하기 위해 사용됩니다. wait()는 잠금을 해제하고 스레드를 대기 상태로 전환하며, notify()는 대기 중인 스레드 중 하나를 깨우고, notifyAll()은 대기 중인 모든 스레드를 깨웁니다.
Q. 멀티스레드 애플리케이션에서 wait()과 notify()가 효과적으로 사용될 수 있는 시나리오를 설명해주세요.
✅ 이러한 메서드들은 생산자-소비자 시나리오에서 효과적으로 사용됩니다. 생산자 스레드는 버퍼에 공간이 생길 때까지 wait()를 사용하여 기다릴 수 있으며, 소비자 스레드는 데이터를 소비하고 버퍼에 공간이 생기면 notify()를 사용하여 생산자를 깨울 수 있습니다.
Q. 동기화가 멀티스레딩에서 왜 중요하며, 자바에서는 어떻게 동기화를 달성할 수 있나요?
✅ 동기화는 경쟁 조건을 방지하고 공유 리소스의 데이터 무결성을 유지하기 위해 멀티스레딩에서 중요합니다. 자바에서는 임계 구역의 코드를 지정하기 위해 synchronized 키워드를 사용하여 동기화를 달성할 수 있습니다.
참고자료
[Java] Thread
[자바의 정석 - 기초편] ch13-1 쓰레드 ~ [자바의 정석 - 기초편] ch13-34~36 wait()과 notify()