프로그램
실행이 안된 상태를 의미하며, 프로그래밍 코드의 집합체를 의미한다.
프로세스
프로그램의 한 단위를 말하며 실행 중인 프로그램으로 메모리에 독립적으로 저장되어 실행된다.
스레드
프로그램 내에서 동작하는 작업 단위를 말하며 스레드를 통해 동시에 여러 가지 작업을 할 수 있다.
- 단일 쓰레드
처리 경로를 한 개만 가지고 있기 때문에 직렬적이다.
한 번에 하나씩 처리하기 때문에 상대적으로 비효율적이다.
하지만 하나의 작업에 문제가 발생하더라도 다른 작업은 시작하지 않았기 때문에
다른 작업에는 문제가 발생하지 않는다.
따라서 안정성이 보장되고 설계 시 멀티쓰레드에 비해 쉽다.
- 멀티 쓰레드
하나의 프로세스를 동시에 처리하는 것처럼 보이지만 매우 짧은 단위로 분할해서 차례로 처리한다.
여러 개의 처리 경로를 가질 수 있도록 하며, 동시 작업이 가능해진다.
설계하기 어려우며, 하나의 쓰레드 문제 발생 시 모든 쓰레드에 문제가 발생하게 된다.
멀티 쓰레드로 설계했다면, 처리량 증가, 효율성 증가, 처리비용 감소의 장점이 있기 때문에
단점을 감수하고 설계하는 편이다.
멀티 쓰레드 구현 방법
핵심 : run() 메소드 재정의 (오버라이딩)
1. Thread 클래스 상속
Thread 클래스를 상속 받게 되면 run() 메소드 구현이 강제되어 아래와 같이 구현해야 한다.
class Test01 extends Thread {
...
@Override
public void run() {
// 실행할 문장
}
...
}
2. Runnable 인터페이스 구현
기존에 상속되어 있는 클래스를 스레드로 만들려면 Runnable 인터페이스를 상속하여 구현할 수 있다. 아래와 같이 Runnable을 매개 값으로 갖는 생성자를 호출해 생성한다.
Thread th = new Thread(Runnable을 상속한 인스턴스);
동기화(Synchronized)
자원 공유 시 연산을 건너뛰는 이상한 문제가 생긴다. 이는 속도가 빠르기 때문에 이미 처리한 것으로 생각하고 넘어가기 때문이다. 이런 상황에서는 문제가 생기는 코드 또는 메소드 부분만 단일 처럼 처리할 수 있고, 이 때 사용하는 문법이 동기화이다.
1. 동기화 블럭 : 소스코드에 부분적으로 동기화 영역을 작성한다.
synchronized(mutex) {
// 동기화된 코드;
}
2. 동기화 키워드 : 메소드 또는 클래스 등에 키워드를 작성하여 전체적인 부분을 동기화해준다.
접근자 synchronized 리턴타입 메소드명(매개변수, ...) {
// 동기화된 코드;
}
스레드 상태
상태 | 상수 | 설명 |
생성 | NEW | 스레드 객체가 생성되었지만 아직 start() 메소드가 호출되지 않은 상태 |
대기 | RUNNABLE | 실행 대기 또는 실행 상태로 언제든지 갈 수 있는 상태 |
일시정지 | WATING | 다른 스레드가 종료될 때까지 대기하는 상태 |
TIMED_WATING | 주어진 시간 동안 대기하는 상태 | |
BLOCKED | 락이 풀릴 때까지 대기하는 상태 | |
종료 | TERMINATED | 수행을 종료한 상태 |
스레드의 상태는 생성, 대기, 일시정지, 종료 4가지로 구분하며, 상태 구분에 따른 값을 상수로 가지고 있다.
스레드는 '생성 --> 대기 <--> 실행 --> 종료' 순으로 진행되고, 실행 순서를 설명하자면 스레드 객체를 생성하고 start() 메소드를 호출하면 실행 대기 상태가 된다. 실행되지 않고 기다리고 있다가 하나의 스레드가 선택되면, CPU가 run() 메소드를 실행하도록 한다. 이 때가 실제 실행 상태를 의미하고 run()이 실행되는 도중에 실행 대기상태로 돌아갈 수 있다. 더이상 실행할 코드가 없으면 실행을 멈추게 되고 이 상태를 종료 상태라고 한다.
스레드 sleep()
sleep 메소드는 주어진 시간 동안 스레드를 정지시키는 메소드이다. 해당 기능은 모든 스레드를 대기시키며, 주어진 시간이 지나면 풀리게 된다.
Thread.sleep(딜레이 할 시간); // 1000당 1초
wait()와 notify()
여러 개의 스레드가 동시에 동작할 경우 , 하나의 스레드가 완료되어야 다음 스레드가 동작할 수 있는 경우가 있다. 그 때 사용하는 메소드가 wait() 와 notify() 메소드이다. wait() 메소드는 스레드를 대기시킬 때, notify()는 대기중인 스레드를 다시 동작 시킬 때 사용한다.
예제
public class Test01 {
private int stackCount = 10;
pubilc synchronized void addStack(int stackCount) {
this.stackCount += stackCount;
if(this.stackCount >= 10) {
System.out.println("=== 스레드 깨우기 ===");
notify(); // 대기중인 스레드 동작 시키기
}
}
pubilc synchronized void addStack(int leaveCount) {
try {
if(leaveCount > this.stackCount) {
this.stackCount = 0;
} else {
this.stackCount -= leaveCount;
}
if(this.stackCount == 0) {
System.out.println("=== 짐 없음 대기 ===");
wait(); // 스레드 대기시키기
System.out.println("=== 짐 없음 완료 ===");
}
}
catch(Exception e) {
e.printStackTrace();
}
}
public int getStackCount() {
return this.stackCount;
}
}
'JAVA > JAVA 정리' 카테고리의 다른 글
[JAVA] MVC 패턴 (0) | 2023.06.06 |
---|---|
[JAVA] 파일 입출력 (4) | 2023.06.04 |
[JAVA] 컬렉션 프레임워크 (List 컬렉션, Set 컬렉션) (0) | 2023.06.01 |
[JAVA] 예외처리방법 예제 (try catch) (2) | 2023.05.31 |
[JAVA] 예외 처리 (0) | 2023.05.31 |