1. Thread 클래스와 Runnable 인터페이스 2. 스레드의 상태 3. 스레드의 우선순위 4. Main 스레드 5. 동기화 6. 데드락
1. Thread 생성
Thread 클래스 이용
Thread 클래스는 Runnable 인터페이스를 구현한 클래스다.
Thread 클래스가 다른 클래스를 확장할 필요가 없을 경우에 사용한다.
public class ThreadSample extends Thread {
@Override
public void run() {
System.out.println("ThreadSample 메소드");
}
}
Runnable 인터페이스 이용
Thread 클래스가 다른 클래스가 활장할 필요가 있을 때 사용한다.
Runnable <- Thread <- ThreadSample
public class RunnableSample implements Runnable{
@Override
public void run() {
System.out.println("RunnableSample 메소드");
}
}
실행은 아래 코드와 같이 한다.
start() 메소드가 끝날 때까지 기다리지 않고, 다음 줄의 start() 메소드를 실행한다.
새로운 스레드이므로 run() 메소드가 종료될 때까지 기다리지 않고 다음 줄로 넘어간다.
스레드는 항상 순서대로 작동하진 않는다. 컴퓨터 성능에 따라 다르며 매 실행마다 결과가 다르다.
public class RunThreads {
public static void main(String[] args) {
runBasic();
}
public static void runBasic() {
RunnableSample runnable = new RunnableSample();
new Thread(runnable).start();
ThreadSample thread = new ThreadSample();
thread.start();
System.out.println("RunThreads.runBasic() method is ended.");
}
}
/*
This is RunnableSample's run() method.
RunThreads.runBasic() method is ended.
This is ThreadSample's run() method.
*/
2. 스레드 상태
new : 스레드 객체는 생성되었지만 시작되지 않은 상태
runnable : 스레드 실행중인 상태
blocked : 스레드가 실행 중지 상태며, 모니터 락이 풀리기를 기다리는 상태
waiting : 스레드가 대기중인 상태
timed_waiting : 특정 시간만큼 스레드가 대기중인 상태
terminated : 스레드가 종료된 상태
3. 스레드 우선순위
static int MAX_PRIORITY : 스레드가 가질 수 있는 최대 우선순위 명시
static int MIN_PRIORITY : 스레드가 가질 수 있는 최소 우선순위 명시
static int NORM_PRIORITY : 스레드가 생성될 때 가지는 기본 우선순위 명시
getPriority()와 setPriority() 메소드를 통해 스레드의 우선순위를 반환하고 변경한다.
우선순위는 1~10 까지며, 비례적인 값이 아닌 상대 값이다.
4. Main 스레드
Java를 실행하기 위해 우리가 실행하는 main() 메소드가 메인 스레드다.
따로 스레들르 실행하지 않고 main() 메소드만 실행하는 것을 싱글 스레드 애플리케이션이라고 한다.
메인 스레드에서 스레드를 생성하여 실행하는 것은 멀티 스레드 애플리케이션이라고 한다.
5. 동기화
여러 개의 스레드가 한 개의 리소스를 사용하려고 할 때, 사용하려는 스레드를 제외한 나머지 스레드들의 접근을 막는 것이다.
Synchronized 키워드
메소드 자체를 synchronized로 선언한다.
혹은 메소드 내 특정 문장만 synchronized로 감싼다.
100번의 반복문으로 1을 더하는 함수를 스레드로 만들고 스레드를 두 번 시작하면 200이라는 원하는 결과를 얻지 못한다.
synchronized를 사용하면 200을 얻을 수 있다.
// synchronized methods
public class CommonCalculate {
private int amount;
public CommonCalculate() {
amount=0;
}
public synchronized void plus(int value) {
amount += value;
}
public synchronized void minus(int value) {
amount -= value;
}
public int getAmount() {
return amount;
}
}
// synchronized statements
public class CommonCalculate {
private int amount;
private int interest;
public static Object interestLock = new Object();
public CommonCalculate() {
amount=0;
}
public void addInterest(int value) {
synchronized (interestLock) {
interest+=value;
}
}
public void plus(int value) {
synchronized (this){
amount += value;
}
}
public void minus(int value) {
synchronized (this){
amount -= value;
}
}
public int getAmount() {
return amount;
}
}
6. 데드락
멀티 스레드 프로그래밍에서 동기화로 인해 두 개의 스레드가 서로가 가지고 있는 락이 해제되길 기다리는 상태다.
어떤 작업도 실행되지 못하고 서로 상대의 작업이 끝나길 기다리는 상태다.
데드락 발생 조건
상호 배제 : 한 자원에 대해 여러 스레드 동시 접근 불가
점유와 대기 : 자원을 가지고 있는 상태에서 달느 스레드가 사용하고 있는 자원 반남 기기다림
비선점 : 다른 스레드의 자원을 실행 중간에 강제로 가져오지 못 함
환형대기 : 각 스레드가 순환적으로 다음 스레드가 요구하는 자원을 가지고 있음
public class DeadlockSample {
public static final Object LOCK_1 = new Object();
public static final Object LOCK_2 = new Object();
public static void main(String args[]) {
ThreadSample1 thread1 = new ThreadSample1();
ThreadSample2 thread2 = new ThreadSample2();
thread1.start();
thread2.start();
}
private static class ThreadSample1 extends Thread {
public void run() {
synchronized (LOCK_1) {
System.out.println("Thread 1: Holding lock 1...");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
System.out.println("Thread 1: Waiting for lock 2...");
synchronized (LOCK_2) {
System.out.println("Thread 1: Holding lock 1 & 2...");
}
}
}
}
private static class ThreadSample2 extends Thread {
public void run() {
synchronized (LOCK_2) {
System.out.println("Thread 2: Holding lock 2...");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
System.out.println("Thread 2: Waiting for lock 1...");
synchronized (LOCK_1) {
System.out.println("Thread 2: Holding lock 1 & 2...");
}
}
}
}
}
/*
Thread 1: Holding lock 1...
Thread 2: Holding lock 2...
Thread 1: Waiting for lock 2...
Thread 2: Waiting for lock 1...
*/