자바에서 스레드는 동시에 여러 작업을 수행할 수 있게 해주는 중요한 기능이다. 스레드는 프로세스 내에서 독립적으로 실행되는 흐름을 말하며, 자바에서는 멀티스레딩을 통해 여러 스레드를 생성하고 동시에 실행할 수 있다. 자바의 모든 프로그램은 기본적으로 하나의 스레드에서 시작하며, 필요에 따라 추가 스레드를 생성하여 작업을 분리할 수 있다.
프로세스
:싱글 스레드
:멀티 스레드
:Thread 클래스 상속
:Thread 클래스를 상속받아 스레드를 생성할 수 있다. Thread 클래스를 상속받은 후, run() 메소드를 오버라이딩하여 스레드에서 수행할 작업을 정의한다.
class MyThread extends Thread {
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) {
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
thread1.start(); // 스레드 시작
thread2.start(); // 두 번째 스레드 시작
}
}
MyThread
클래스는 Thread 클래스를 상속받아 run()
메소드를 오버라이드한다.start()
메소드는 새로운 스레드를 시작하며, 내부적으로 run()
메소드가 실행된다.Thread.sleep(1000)
는 스레드를 1초 동안 대기 상태로 만든다.Runnable 인터페이스 구현
:Runnable 인터에시를 구현한 클래스를 만들고, run() 메소드를 정의하는 방법이다. 이 방법은 자바에서 다중 상속을 지원하지 않기 때문에, Thread 클래스를 상속받지 않고 다른 클래스를 상속해야 할 경우 유용하다.
class MyRunnable implements Runnable {
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();
}
}
start()
: 스레드를 시작하며, 내부적으로run()
메소드를 호출한다.run()
: 스레드가 실행할 코드를 포함하며,start()
메소드에 의해 호출된다.sleep(long millis)
: 지정한 시간(밀리초) 동안 스레드를 일시 정지시킨다.join()
: 현재 스레드가 다른 스레드의 종료를 기다리게 만든다.yield()
: 현재 실행 중인 스레드가 다른 스레드에게 CPU 자원을 양보하도록 요청한다.
interrupt()
: 스레드의 대기 상태를 중단한다.
스레드의 상태는
Thread.State
를 통해 확인할 수 있다.
NEW
: 스레드가 생성되었지만 아직 start() 메소드가 호출되지 않은 상태RUNNABLE
: 실행 가능한 상태. JVM이 스레드를 실행할 준비가 되어 있고, CPU에 의해 실행될 수 있는 상태.BLOCKED
: 스레드가 모니터 락을 얻기 위해 디기 중인 상태. 동기화된 블록이나 메소드에서 다른 스레드에 의해 락이 걸려 있을 떄 나타난다.WAITING
: 스레드가 다른 스레드의 작업이 완료될떄까지 대기 중인 상태.TIMED_WAITING
: 지정된 시간 동안 대기 중인 상태. slepp() 이나 wait(long timeout) 호출 시 발생한다.TERMINATED
: 스레드의 실행이 종료된 상태.
스레드 간의 협력은
wait()
,notify()
,notifyAll()
메소드를 통해 이루어진다. 이들은 주로 동기화 블록에서 사용되며, 한 스레드가 작업을 마치고 다른 스레드를 깨우거나 일시적으로 대기 상태로 만들 수 있다.
동기화 매커니즘
:synchronized
키워드를 사용하여 블록이나 메소드를 동기화할 수 있다.class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
};
Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("Final count : " + counter.getCount());
}
}
예시코드에서 increment()
메소드는 synchronized
로 동기화 되어 여러 스레드가 동시에 호출하더라도 문제가 발생하지 않도록 보호되게 된다.
멀티스레드 애플리케이션에서 스레드를 너무 많이 생성하는 것은 성능에 부담이 될 수 있다. 이를 해결하기 위해 자바는 스레드 풀이라는 기능을 제공한다. 스레드 풀은 미리 스레드를 생성해 두고 필요할 때 재사용하여 효율적으로 자원을 관리한다.
import Java.util.concurrent.ExecutorService;
import Java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3); // 3개의 스레드
for(int i = 0; i < 5; i++) {
executorService.submit(() -> {
System.out.println(Thread.currentThread().getName() + " is working");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executorService.shutdown(); // 스레드 풀 종료
}
}
스레드를 중단하는 것은 스레드가 동작하는 동안 종료시키는 작업을 의미한다. 자바에서 스레드를 강제로 종료하는 것은 권장되지 않는다.
interrupt()
메소드를 사용하여 스레드에 인터럽트를 걸고, 스레드 내부에서 이를 처리하는 방식으로 구현하는 것이 일반적이다.
class MyThread extends Thread {
public void run() {
try {
for(int i = 1; i) {
System.out.println("Thread is working : " + i);
Thread.sleep(1000); // 스레드가 1초 대기
}
} catch (InterruptedException e) {
System.out.println("Thread was interrupted during sleep."):
}
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(3000); // 3초 후 인터럽트
thread.interrupt(); // 스레드 중단 요청
}
}
책을 보면서 내용 요약과 예시 코드를 작성하면서 스레드의 기본 개념과 작동 방식을 알게 되었다.
하지만 완전히 이해한건 아니라 기록을 해두고 시간날때마다 가끔씩 들여다보면서 개념을 확실하게 확립해야 할 것 같다.