본 게시글은 대학 전공수업을 들으며 노션에 정리한 내용을 블로그로 옮긴 것으로, 노션 웹을 통해 최적화된 형태로 읽으시길 권장드립니다.(➡️ 노션 링크)
13강 멀티 스레드 프로그래밍
프로세스와 스레드
Java 프로그램은 하나의 프로세스로 만들어져 실행된다.
- 프로세스 : 프로그램의 통상적 실행 단위로, 자원을 확보하고 있는 ‘실행 중인 프로그램’
지금까지는 1프로세스 1스레드, 1개 스레드에서 main()가 호출되며 실행됨(단일스레드)
- 스레드 : 프로세스 내에 있는 소규모 실행 흐름으로, ‘경량 프로세스’
⇒ 멀티스레드
: 하나의 프로세스 내에서 여러 스레드가 동시 실행.
멀티스레드
: 하나의 프로세스 내에서 동시 실행되는 여러 스레드
멀티스레드를 사용할 경우, Main스레드에서 자식 스레드를 만들며 여러 스레드가 동시에 독립적으로
실행되고 종료될 수 있다.
Thread 클래스
- 스레드의 생성과 관리를 위한 메소드 제공
- 스레드 생성을 위해 Thread 클래스 객체가 필요함
- 주요 생성자
생성자 | 설명 |
---|---|
Thread() | 스레드 생성. 이름은 자동으로 ‘Thread-n’으로 주어짐 |
Thread(String name) | 이름을 name으로 지정해 생성 |
Thread(Runnable target) | 스레드 생성, 실행되며 target객체의 run()이 실행 (이름은 자동) |
Thread(Runnable target, String name) | 위와 동일하나 이름을 name으로 지정 |
static Thread currentThread() | 실행중인 스레드 객체의 참조값 리턴 |
String getName() | this 스레드 이름 리턴 |
void setNameI(String name) | this 스레드 이름 name으로 변경 |
int getPriority() | this 스레드 우선순위 리턴 |
void setPriority(int newPriority) | this 스레드 우선순위를 newPriority로 변경 |
void start() | run() 호출 → this 스레드 실행 |
스레드 생성과 실행
- Thread 유형 객체 t 생성
- t.start() 호출
- 스레드 실행 시작 : run()메소드 호출
실행방법 1 : Thread 클래스를 상속받는 클래스
- Thread0과 1은 독립적으로 실행되기때문에 출력 순서는 달라질 수 있다.
- Thread 클래스를 상속받는 MyThread 클래스를 생성 후 start()
package lecture13;
class MyThread extends Thread {
//run() '재정의' : this스레드 이름 리턴
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName());
}
}
}
public class ThreadEx1 {
public static void main(String args[]) {
Thread t1 = new MyThread();
t1.start();
Thread t2 = new MyThread();
t2.start();
System.out.println("main");
}
}
실행방법 2 : Runnable 인터페이스 구현
Thread객체를 생성할 때, Runnable객체를 인자로 사용함.
따라서 정의된 MyThread 클래스는 Thread가 아님!
⇒ Thread 객체로 생성한 방법1과 비교해, 더 유연한 스레드 실행 방식.
package lecture13;
class MyThread2 implements Runnable {
//run() '구현' : 실행중인 스레드 객체 참조값 리턴
public void run() {
for (int i = 0; i < 10; i++) {
//
System.out.println(Thread.currentThread().getName());
}
}
}
public class ThreadEx2 {
public static void main(String[] args) {
Thread t1 = new Thread(new MyThread2(), "스레드 0");
t1.start();
Thread t2 = new Thread(new MyThread2(), "스레드 1");
t2.start();
System.out.println("main");
}
}
멀티스레드 실행
각 스레드는 정해진 순서 없이 독립적으로 실행됨
⇒ 실행 결과는 매번 다를 수 있으며, 예측할 수 없음.
main스레드는 다른 스레드를 시작시킴. 마찬가지로 다른 스레드와 독립적으로 실행/종료됨.
스레드 제어하기
스레드 상태
: 생성된 스레드는 CPU를 얻어 실행되고, 종료될 때 까지 여러 상태 변화를 겪음
상태 | 설명 |
---|---|
Startable | 객체 생성 / start() 실행 전 |
Runnable | start() 호출 됨 / CPU 획득 전 |
Running | CPU 얻어 실행 중 |
NotRunning | 실행 중이였다가 CPU 잃고 중단 / Blocked, Waiting, Timed-Waiting |
Dead | run() 메소드 종료 |
Thread State Transition
스레드의 상태제어 메서드
void setPriority(int newPriority)
- 스레드 우선순위 변경 : 우선순위가 높은 스레드가 CPU를 얻을 확률이 높음
static void sleep((long millis) throws InterruptedException
- millis 시간만큼 실행을 멈추고 NotRunning 상태로 들어감
- 다른 스레드가 interrupt() 메서드로 꺠우면, InterruptedException예외가 발생
static void yield()
- 잠시 실행을 멈추고 Runnable로 들어감 → 다른 스레드에게 양보
void join() throws InterruptedException
- 종료될 때 까지 기다림
- 실행중이였던 스레드는 Not Running으로 들어감.
- 다른 스레드가 깨워주면 예외가 터지며 리턴
void interrupt()
- 스레드를 인터럽트 시켜 Runnable 상태로 바꿈.
- 스레드가 중단된 상태(wait() / join() / sleep()에 의해)였을 때 사용됨
void wait() throws InterruptedException
- 스레드가 대기상태로 감
- 다른 스레드가 이 객체를 notify() 호출할 때 까지 기다림.
void notify()
- wait()을 호출 → 대기중인 스레드 깨워줌.
- synchronized 메소드의 내부에서만 호출 가능.
더 자세한 내용은 공부하지 말라고 하신다…(굿)
예시코드
package lecture13; class MyThread3 implements Runnable { static int count = 0; public void run() { for (int i = 0; i < 50; i++) { String thd_name = Thread.currentThread().getName(); System.out.print(thd_name + " "); //thd1이면 Runnable로 들어가 멈추고 다른 스레드에게 양보. //(단, 반드시 양보하는 것은 아님) if (thd_name.equals("thd1")) { Thread.yield(); } count++; if (count % 10 == 0) { System.out.println(); } } } } public class ThreadYield { public static void main(String args[]) { Thread my_thread1 = new Thread(new MyThread3(), "thd1"); Thread my_thread2 = new Thread(new MyThread3(), "thd2"); my_thread1.start(); my_thread2.start(); } }
1이 먼저 출력 중 → 1보고 양보하라고 함 → 2가 먼저 출력된 후 1이 출력 됨.
join()으로 제어하기
interrupt()로 제어하기
스레드간 간섭(Thread Interference)
여러개의 스레드가 하나의 공유 객체에 동시 접근하는 경우 데이터 무결성이 깨짐
+1, -1을 하면 0이 되어야 하는데 간섭으로 인해 최종 값이 -1이 되버림.
스레드 동기화(Synchronized)
서로 다른 스레드들이 공유 자원을 다룰 때 데이터 무결성을 보장하는 것
한번에 오직 한개의 스레드만이 공유 객체에 접근하도록 동기화 하는 것(상호 배제)
사용방법 2가지
상호배제원칙
키워드 synchronized
동기화 메소드 또는 블록을 제공
수정할 때 다른 스레드에서 같은 코드를 수행할 수 없게 함.
synchronized 메소드
: 스레드 동기화를 위한 키워드 → 한번의 하나에 스레드에 의해서만 실행
- 이 메소드를 실행하려면, 메소드를 호출한 객체에 대한 lock을 얻어야 함.
- 일부 블록만 동기화 하는것도 가능
- synchronized(객체) {…}
- 이때의 객체는 공유자원으로 대개 this를 사용
- synchronized(객체) {…}
'Back-End > Java' 카테고리의 다른 글
(전공 정리) 12강 - 스트림 : 중간연산(필터링,매핑,정렬,루핑), 종료연산(집계, 매칭) (0) | 2024.06.22 |
---|---|
(전공 정리) 11강 - 컬렉션 : JCF, Iterator, 자료구조, HashSet, ArrayList, LinkedList, HashMap (0) | 2024.06.22 |
(전공 정리) 9강 - Java.io : 입출력스트림, 파일 입출력 (0) | 2024.06.22 |
(전공 정리) 8강 - java.lang 패키지: Object, String, StringBuffer (0) | 2024.06.22 |
(전공 정리) 7강 - 패키지와 예외처리 (0) | 2024.06.22 |
(전공 정리) 6강 - 제네릭, 람다식 (0) | 2024.06.22 |