멀티 쓰레드 :
하나의 프로그램 내에서 여러 작업들을 동시에 수행할 수 있다.
=> 이제 하나가 끝날 때 까지 기다리는 것이 아니라 여러 작업을 수행할 수 있게된다.
단위: 쓰레드 - 프로세스 내에서 메모리를 공유한다. (이 때문에 문제가 발생하기도 한다. 후에 설명)
=> 쓰레드 간에 데이터를 쉽게 주고 받는다.
메모리를 공유하며 독립적으로 동작하기 때문에 빠른 응답을 하고, 이를 동시에 접근하기 때문에 동기화 문제가 발생할 수 있다.
예시) 워드 프로세서에서 사용자의 입력을 받는 쓰레드와 맞춤법 검사를 하는 쓰레드가 동시에 작동하는 현상
예시) 여러 쓰레드가 동시에 동일한 데이터에 접근을 하여 수정하려고할 때 데이터의 일관성이 깨진다.
자바의 멀티 쓰레드
특징:
실행 중인 쓰레드가 하나라도 있으면 프로그램이 종료되지 않는다. => 대기 시간 발생
main 쓰레드
- 모든 자바 프로그램은 메인 쓰레드가 main() 메소드를 실행하며 시작
- 첫 코드부터 순차적으로 실행
동시성, 병렬성
동시성: 하나의 cpu가 작업을 번갈아 쪼개가며 실행 -> 사람의 눈에는 독립적으로 동시에 실행되는 것으로 보인다.
병렬성: 여러 cpu가 실제로 각각의 작업을 실행 -> 코어의 수보다 쓰레드수가 작으면 병렬성이 보장되지만 쓰레드의 개수가 코어보다 많다면 순서를 정해주어야한다. (스케줄링)
쓰레드 생성 & 실행
쓰레드를 만드는 방법은 두 가지 이다.
- Thread 클래스 상속
- Runnable 인터페이스 사용
Thread 클래스 상속
class MyThread extends Thread{
public void run(){
}
public void work(){
for(int i=0;i<10;i++){
System.out.println("thread 실행 중 : (i)");
}
}
}
Runnable 인터페이스 사용
class MyRunnable implements Runnable{
public void run(){
System.out.println("Runnable 실행 중 : " + Thread.currentThread().getName());
}
}
main에서 실행
public class Main{
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start();
Thread t2 = new Thread(new MyRunnable());
t2.start();
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<10;i++) {
System.out.println("짝! " + i);
}
}
});
t3.start();
}
++람다식 사용
Thread t4= new Thread(() -> {
System.out.println("람다식 쓰레드 실행! ");
});
람다식: 익명함수를 사용 (Runnable 을 사용한다. )
언제 사용하나?
- 한 번만 사용할 때
- 간단한 로직일 때
- 그 자리에서 바로 정의하고 사용할 때
Sleep:
sleep 함수를 이용해 cpu를 효율적으로 사용하고, 여러 쓰레드가 실행되도록한다.
Thread.sleep(sleepTime);
사용 예시
while (gameRunning) {
updateGame();
renderGame();
Thread.sleep(16); // ~60 FPS
}
cpu를 100% 활용 하지 않기 때문에, 부드러운 애니메이션, cpu 효율성, 안정적인 성능을 확보할 수 있다.
여기까지 배웠으면
쓰레드의 주요 메소드를 알아보자.
주요메소드:
- void start() : 쓰레드를 시작한다. run()을 호출하여 코드 실행
- void run() : 쓰레드에서 실행될 코드를 작성
- static void sleep(long mills): 현재 실행 중인 쓰레드를 시간동안 일시정지
- void interrupt(): 현재 Thread에 신호를 보내 중단하도록 알림을 보낸다.
- void join() , join(long mills) : 다른 Thread가 종료될때까지 현재 Thread를 대기시킨다. 시간 지정도 가능
쓰레드의 우선순위: 쓰레드는 우선순위가 없다.
이유: JVM은 OS의 스케줄러에 의존한다. 해당 우선순위가 전달되어도 이 값을 무시하거나 약하게 반영할 수 있다.
실습
Thread.getName(), setName()
Thread p1=new Player1("짱구", "이슬이누나~",20);
System.out.println(p1.getName()); //Thread-0 출력
p1.setName("짱구");//쓰레드의 이름을 지정할 수 있다.
System.out.println(p1.getName()); //짱구 출력
쓰레드의 순서
package lab3;
public class Main {
public static void main(String[] args) {
Thread p1=new Player1("짱구", "이슬이누나~",100);
Thread p2=new Player1("맹구", "돌이다",100);
Thread p3=new Player1("흰둥이", "멍멍멍",100);
p1.start();
p2.start();
p3.start();
}
}

먼저 실행한 짱구 쓰레드가 맨 마지막에 끝난다.
ð 쓰레드에는 순서가 중요하지 않다. 먼저 실행 된 것이 먼저 끝날 것이라는 보장이 없다.
만약 작업 순서가 반드시 지켜져야 한다면, join()과 같은 쓰레드 동기화 기능을 사용하여 명시적으로 순서를 제어해야한다.
왜 그럴까? (OS 스케줄러의 역할)
스케줄러는 다음과 같은 여러 가지 요소를 고려하여 어떤 쓰레드를 먼저 실행할지 결정한다.
- 쓰레드의 우선순위: 더 중요하다고 표시된 쓰레드를 먼저 실행
- 작업의 종류: 어떤 쓰레드는 파일 입출력처럼 기다리는 시간이 길고, 어떤 쓰레드는 계속 계산만 한다. 스케줄러는 기다리는 쓰레드를 잠시 멈추고 계산하는 쓰레드를 실행하는 등 효율적으로 CPU를 사용하려고 함.
- 시스템의 전체적인 상태: 다른 프로그램들이 얼마나 실행되고 있는지도 영향을 준다.
'짱구 쓰레드'를 가장 먼저 start() 시켰다고 해도, 스케줄러가 다른 쓰레드(예: '맹구 쓰레드', '흰둥이 쓰레드')를 먼저 실행하도록 잠깐씩 CPU를 할당해 준다.
정리:
핵심 - 자바의 스레드 우선순위는 '절대적인 실행 순서'를 보장하지 않으며, 운영체제(OS)에 따라 다르게 동작하기 때문에 의도한 대로 작동하지 않을 가능성이 크다. (자바 스레드 우선순위는 존재)
Thread.interrupt()
intterupt() 는 중단 신호를 보낸다.
신호만 보내는 것이기 때문에 쓰레드를 멈추는 것은 쓰레드의 내부 코드 책임이다.
InterruptedExcexption을 처리하여 return을 하거나, isInterrupted() 플래그를 확인하여 반복문을 break 또는 return하면 쓰레드가 종료된다.
//5%확률로 interrput 신호 보내기
if ((int)Math.random()*1000)%100<5){
this.interrupt();
}
//감지
if(Thread.interrupted()){ //신호가 들어왔는지 확인
return;//종료
}
중간정리
- 멀티쓰레드를 구현하기 전에 몇 개의 작업을 병렬로 실행할지 결정해야한다.
- 자바에서 다중 상속이 불가 -> Runnable 인터페이스를 사용하는 것이 좋다.
- Runnable 인터페이스를 사용한다면 고수준의 쓰레드 관리 API도 사용이 가능하다. (Runnable과 Thread로 분리하기 때문)
주의사항:
- run()메서드 종료 -> 스레드도 종료
- 한번 종료한 스레드는 다시 start 불가능! (만약 다시 해당 스레드를 쓰고 싶다면 객체를 새로 생성하고 start를 호출해야한다.
- 한 스레드에서 다른 스레드를 강제 종료할 수 없다.
lab 알낳기 코드
닭이 오른쪽 방향키를 누를 때 이동하고, 클릭하면 egg가 생성되고 아래로 떨어진다.
이 상황에서 thread로 구현해야하는 것은 egg이다.
이유: 알이 생성되고 아래로 떨어지고, 색이 바뀌는 상황에 thread가 쓰여야하기 때문이다. 닭은 특정 순간에 발생하는 이벤트를 다루기 때문에 굳이 스레드로 만들 필요가 없다.
알은 생성된 시점부터 떨어져서 사라질 때까지 자신의 일을 해야한다. 알1과 알2는 생성 된 후 서로 영향을 주지 않고, 각자의 속도와 타이밍에 맞춰 독립립적으로 움직여야한다.
이렇게 각자 고유한 생명주기를 가지고, 동시에 실행되어야하는 객체가 바로 스레드로 구현할 대상이다.
Thread t = new Thread((Runnable)egg);
button인 egg 객체에 스레드를 장착시킨다.
한 스레드 안에 run안에 있는 코드는 순차적으로 실행된다.
기억 할 것:
주요 메서드, 쓰레드의 주의사항 (3가지), 쓰레드 생성시 고려해야하는 것들
'자바' 카테고리의 다른 글
| week5: 자바 SOLID원칙 (0) | 2025.10.03 |
|---|---|
| week4: 자바 Thread -2 (0) | 2025.10.01 |
| week3. 자바 Collections (set,list,map ) (0) | 2025.09.23 |
| week2: 자바 프로그래밍 (static, final, 싱글톤) (0) | 2025.09.19 |
| 새 시작& 자바 개념 복습 (0) | 2025.09.07 |