이전 내용
[java] java 스레드(thread) - 멀티, 메인, 작업 / 동기화 메소드
이전 내용 [java] java.lang 패키지이전 내용 [java] 예외 (클래스, 처리), 다중 catch, 예외 떠넘기기, String args[]이전 내용 [java] 인터페이스 상속, 중첩 클래스, 중첩 인터페이스이전 내용 [java] instanceo
puppy-foot-it.tistory.com
스레드 제어
스레드를 생성하고 시작하면 스레드는 다양한 상태를 가지게 되는데, 스레드의 상태는 자동으로 변경될 수도 있고, 코드에 의해 변경될 수도 있다.
스레드 객체 생성 후 start() 메소드를 호출하면 바로 실행되는 것이 아니라 실행 대기 상태(언제든 실행될 준비가 되어 있는 상태)가 된다. 실행 상태의 스레드는 run() 메소드를 모두 실행하기 전에 다시 실행 대기 상태로 돌아갈 수 있고, 실행 대기 상태에 있는 다른 스레드가 선택되어 실행 상태가 되기도 한다.
[스레드 상태의 상세 설명]
스레드는 여러 상태를 가지며, 각 상태는 실행하는 과정에서의 특징을 나타내고 있다. 이를 통해 프로그램의 흐름과 성능을 효과적으로 관리할 수 있다.
1. 새로운 상태 (New)
- 스레드 객체가 생성되었지만 아직 실행되지 않은 상태.
- Thread thread = new Thread();와 같이 스레드를 생성하는 코드가 실행되면, 해당 스레드는 새로운 상태에 있다.
Thread thread = new Thread(new Runnable() {
public void run() {
// 스레드가 실행할 코드
}
});
2. 실행 대기 상태 (Runnable)
- 스레드가 실행될 준비가 되어 있고, CPU에 의해 실행되기를 기다리는 상태.
- 이 상태는 CPU가 다른 스레드를 실행 중이라면 해당 스레드는 대기.
- 스레드는 start() 메서드가 호출되면 run() 메서드를 호출하며, 자동으로 이 상태로 전환.
thread.start(); // 스레드 시작
3. 실행 중 상태 (Running)
- 스레드가 CPU에서 실제로 실행되고 있는 상태.
- 이 상태에서는 스레드가 할당된 작업을 수행하며, CPU의 자원을 직접적으로 사용.
4. 대기 상태 (Blocked)
- 스레드가 특정 자원(예: 파일, 데이터베이스)에 접근할 수 없어서 대기하는 상태.
- 다른 스레드가 자원을 점유하고 있을 때 발생. 이 상태에서 스레드는 해당 자원이 해제되기를 기다리고, 해제되면 다시 실행 대기 상태로 전환.
- 스레드를 일시적으로 대기시키기 위해 sleep(milliseconds) 메서드를 사용하여 지정된 시간 동안 실행을 멈추게 할 수 있다.
※ 밀리세컨드(1/1000초)
try {
Thread.sleep(1000); // 1초 대기
} catch (InterruptedException e) {
e.printStackTrace();
}
5. 준비 상태 (Waiting)
- 스레드가 다른 스레드의 작업 완료 또는 특정 신호를 기다리는 상태.
- Object.wait() 또는 Thread.join() 메서드가 호출되면 해당 스레드는 준비 상태로 전환되어, 신호가 올 때까지 대기.
public synchronized int getData() throws InterruptedException {
while (!isDataAvailable) {
wait(); // 데이터가 준비될 때까지 대기
}
isDataAvailable = false;
return data;
}
6. 종료 상태 (Terminated)
- 스레드의 실행이 완료되어 더 이상 실행할 작업이 없는 상태.
- 스레드는 자연스럽게 종료되거나, 예외에 의해 비정상적으로 종료될 수 있다.
- interrupt() 메소드는 스레드가 일시 정지 상태에 있을 때 InterruptedException을 발생시키는 역할을 하며, 이를 이용하면 run() 메소드를 정상 종료할 수 있다. ▶ 즉시 실행되는 것이 아니라, 미래에 일시 정지 상태가 되면 멈춘다.
thread.interrupt(); // 스레드 강제 종료
예제1
Q. 1부터 100까지 구하기
- 1부터 100까지 구하는 스레드 생성
- 메인에서는 총합 출력
- 100까지 다 구하면 종료되도록 설정
public class SumThread extends Thread {
int total;
@Override
public void run() {
synchronized (this) {
for (int i = 1; i <= 100; i++) {
total += i;
System.out.println(i + "을 더한 총합: " + total);
}
System.out.println("총합: " + total);
}
}
}
public class SumTest {
public static void main(String[] args) {
SumThread s = new SumThread();
s.start();
synchronized (s) {
try {
System.out.println("스레드 s가 끝날때까지 대기..");
s.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
예제2
Q. 생산자-소비자 문제
- 생산자(Producer) 스레드가 1부터 5까지의 숫자를 하나씩 생성해 공유 변수에 저장하고, 소비자(Consumer) 스레드가 그 숫자를 읽어 출력하는 프로그램 작성.
- 단, 생산자가 값을 생성한 후 소비자가 읽을 때까지 대기하고, 소비자가 값을 읽은 후 소비자가 다음 값을 생성하도록 wait()와 notify()를 사용해 동기화
- wait(): 현재 스레드를 다른 스레드가 이 객체에 대한 notify() 또는 notifyAll() 메소드를 호출할 때까지 대기
- notify() : 이 객체에 대해 대기중인 스레드 하나를 깨움
- notifyAll() : 이 객체에 대해 대기중인 모든 스레드를 깨움
public class SharedResource {
private int sharedValue = 0;
private boolean isValueProduced = false;
// 생산자 메서드
public synchronized void produce(int value) throws InterruptedException {
while (isValueProduced) { // 이미 값이 생산된 상태 - 소비자가 값을 읽을 때까지
System.out.println("생산자: 값이 이미 존재하여 대기 중..");
wait(); // 현재 객체(this)의 모니터에서 대기
}
// 값 생산
sharedValue = value;
isValueProduced = true;
System.out.println("생산자: " + value + " 생산 완료");
// 소비자에게 알림
notify();
}
// 소비자 메서드
public synchronized void consume() throws InterruptedException {
// 값이 생산되지 않은 경우 생산자가 생산 시까지 대기
while (!isValueProduced) {
System.out.println("소비자: 값이 없어 대기 중..");
wait();
}
// 값 소비
System.out.println("소비자: " + sharedValue + " 소비 완료");
isValueProduced = false;
// 생산자에게 알림
notify();
}
}
public class ResourceTest {
public static void main(String[] args) {
// 공유 자원 가진 객체 생성
SharedResource resource = new SharedResource();
// 생산자 스레드
Thread producer = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
try {
resource.produce(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
// 소비자 스레드
Thread consumer = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
try {
resource.consume();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
// 스레드 실행
producer.start();
consumer.start();
}
}
예제3
Q. 은행 계좌 입출금 시스템
[요구 사항]
1. BankAccount 클래스
- 속성: balance (정수, 계좌 잔액)
- 메서드: a. deposit(int amount): 입금 / b. withdraw(int amount): 출금
- 동기화: 잔액 변경 시 스레드 간 충돌 방지
2. DepositThread와 WithdrawThread 클래스
- Runnable 인터페이스 구현
- 각각 입금과 출금을 반복 수행 (예. 5회씩)
3. 메인 클래스: BankApp
- 초기 잔액 1000원으로 계좌 생성
- 입금 스레드와 출금 스레드 각각 실행
- 최종 잔액 출력
public class BankAccount {
private int balance = 1000; // 잔액 (정수)
// 입금 메서드
public synchronized void deposit(int amount) throws InterruptedException {
balance += amount;
System.out.println("입금: " + amount + ", 잔액: " + balance);
}
// 출금 메서드
public synchronized void withdraw(int amount) throws InterruptedException {
balance -= amount;
System.out.println("출금: " + amount + ", 잔액: " + balance);
}
// 잔액
public int getBalance() {
return balance;
}
public int setBalance() {
return balance;
}
}
public class BankApp {
public static void main(String[] args) {
BankAccount bankacc = new BankAccount();
// 입금 스레드 생성
Thread deposit = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
bankacc.deposit(200);
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
// 출금 스레드 생성
Thread withDraw = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
bankacc.withdraw(300);
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
// 스레드 시작
deposit.start();
withDraw.start();
// 스레드 종료까지 대기
try {
deposit.join();
withDraw.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("최종 잔액: " + bankacc.getBalance());
}
}
다음 내용
'프로그래밍 및 기타 > Java, Spring Boot' 카테고리의 다른 글
[Java] Spring Boot: 인텔리제이(커뮤니티) 다운로드 (0) | 2025.04.14 |
---|---|
[java] 컬렉션 프레임워크, 제네릭 (0) | 2025.04.11 |
[java] java 스레드(thread) - 멀티, 메인, 작업 / 동기화 메소드 (1) | 2025.04.10 |
[java] java.lang 패키지 (0) | 2025.04.09 |
[java] 예외 (클래스, 처리), 다중 catch, 예외 떠넘기기, String args[] (0) | 2025.04.09 |