Java 스레드는 병렬 처리를 통해 애플리케이션의 성능을 최적화할 수 있는 강력한 도구입니다. 스레드를 활용하면 멀티코어 프로세서를 최대한 활용할 수 있고, 사용자 경험을 향상시키는 데 중요한 역할을 합니다. 이번 블로그에서는 자바 스레드의 기초 개념과 기본 사용법에 대해 알아보겠습니다.
스레드란 무엇인가?
스레드는 프로그램의 실행 단위입니다. 자바 프로그램은 기본적으로 하나의 메인 스레드에서 실행되지만, 추가 스레드를 생성하여 여러 작업을 동시에 처리할 수 있습니다. 이러한 병렬 처리는 CPU 자원을 효율적으로 사용하고, I/O 작업 대기 시간 등을 최소화하여 애플리케이션 성능을 향상시킵니다.
자바에서 스레드 생성과 실행
자바에서 스레드를 생성하는 방법은 두 가지가 있습니다:
1. `Thread` 클래스를 상속하는 방법
2. `Runnable` 인터페이스를 구현하는 방법
1. Thread 클래스를 상속하는 방법
`Thread` 클래스를 상속하여 스레드를 생성하는 방법은 간단하지만, 다중 상속이 불가능하다는 단점이 있습니다. 예제를 통해 살펴보겠습니다.
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(getName() + " - " + i);
try {
Thread.sleep(1000); // 1초 대기
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
thread1.start();
thread2.start();
}
}
위 코드에서 `MyThread` 클래스는 `Thread` 클래스를 상속받아 `run` 메서드를 오버라이드합니다. `main` 메서드에서 두 개의 스레드를 생성하고 `start` 메서드를 호출하여 실행합니다.
2. Runnable 인터페이스를 구현하는 방법
`Runnable` 인터페이스를 구현하는 방법은 다른 클래스를 상속받아야 할 때 유용합니다. 다음은 예제 코드입니다.
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " - " + i);
try {
Thread.sleep(1000); // 1초 대기
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Main {
public static void main(String[] args) {
Thread thread1 = new Thread(new MyRunnable());
Thread thread2 = new Thread(new MyRunnable());
thread1.start();
thread2.start();
}
}
여기서 `MyRunnable` 클래스는 `Runnable` 인터페이스를 구현하고, `run` 메서드를 오버라이드합니다. `Thread` 객체를 생성할 때 `Runnable` 객체를 인자로 전달하여 스레드를 실행합니다.
스레드 동기화
멀티스레드 환경에서는 여러 스레드가 동시에 공유 자원에 접근할 때 발생하는 문제를 해결하기 위해 동기화가 필요합니다. 자바에서는 `synchronized` 키워드를 사용하여 동기화를 구현할 수 있습니다.
메서드 동기화
메서드 전체를 동기화하려면 `synchronized` 키워드를 메서드 선언에 추가합니다.
class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
블록 동기화
동기화가 필요한 코드 블록만 `synchronized` 키워드를 사용하여 동기화할 수도 있습니다.
class Counter {
private int count = 0;
public void increment() {
synchronized (this) {
count++;
}
}
public int getCount() {
synchronized (this) {
return count;
}
}
}
위 예제에서 `increment` 메서드와 `getCount` 메서드는 동기화되어 있어 여러 스레드가 동시에 호출하더라도 안전하게 동작합니다.
스레드 상태
스레드는 생애 주기 동안 여러 상태를 가집니다. 주요 상태는 다음과 같습니다:
1. NEW: 스레드가 생성되었지만 아직 시작되지 않은 상태
2. RUNNABLE: 스레드가 실행 중이거나 실행될 준비가 된 상태
3. BLOCKED: 스레드가 모니터 락을 기다리고 있는 상태
4. WAITING: 스레드가 다른 스레드의 작업이 완료되기를 기다리고 있는 상태
5. TIMED_WAITING: 특정 시간 동안 기다리고 있는 상태
6. TERMINATED: 스레드의 실행이 완료된 상태
스레드 상태를 모니터링하여 디버깅과 성능 최적화에 활용할 수 있습니다.
스레드 간 통신
스레드 간 통신은 `wait()`, `notify()`, `notifyAll()` 메서드를 사용하여 구현할 수 있습니다. 이들 메서드는 객체의 모니터에서 동작하며, 스레드 간에 상태 정보를 전달하는 데 사용됩니다.
wait()와 notify() 예제
class SharedResource {
private int value;
private boolean available = false;
public synchronized void produce(int value) throws InterruptedException {
while (available) {
wait();
}
this.value = value;
available = true;
notify();
}
public synchronized int consume() throws InterruptedException {
while (!available) {
wait();
}
available = false;
notify();
return value;
}
}
public class Main {
public static void main(String[] args) {
SharedResource resource = new SharedResource();
Thread producer = new Thread(() -> {
try {
for (int i = 0; i < 5; i++) {
resource.produce(i);
System.out.println("Produced: " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread consumer = new Thread(() -> {
try {
for (int i = 0; i < 5; i++) {
int value = resource.consume();
System.out.println("Consumed: " + value);
Thread.sleep(1500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
producer.start();
consumer.start();
}
}
위 예제에서 `produce`와 `consume` 메서드는 `wait()`와 `notify()`를 사용하여 스레드 간 통신을 구현합니다. 생산자 스레드는 값을 생성하고, 소비자 스레드는 생성된 값을 소비합니다.
'JAVA' 카테고리의 다른 글
Java 17 버전 업그레이드 1탄 (0) | 2024.07.15 |
---|---|
Java 스레드 알아보자 2탄 (0) | 2024.07.13 |
Java GC 알아보자 (0) | 2024.07.06 |
Spring Data JPA 에 대해 알아보자 (0) | 2024.07.04 |
effective java (0) | 2024.07.03 |