멀티태스킹
하나의 CPU가 여러가지 작업을 번갈아 처리하는 방식
동시에 처리하는 것처럼 보이지만 빨리 전환하는 것!
멀티프로세스
여러 CPU 또는 CPU 코어를 이용하여 여러 프로세스 동시 실행
특징: 프로세스간 메모리를 공유하지 않으며 안정성 높음
eg) 브라우저에서 탭마다 별도의 프로세스를 띄움
*프로세스: OS에서 관리하는 실행단위
멀티쓰레드
하나의 프로세스 내에서 여러 작업들을 동시 수행
특징: 프로세스보다 생성/소멸 비용이 낮지만 쓰레드는 프로세스 내에서 메모리를 공유하기 때문에 동기화 문제가 발생할 수 있음
eg) 게임
자바는 실행 중인 쓰레드가 하나라도 있다면 프로세스는 종료하지 않는다!
Thread 생성
public class MyThread extends Thread{
public void run() {
//실행 코드
}
}Thread 클래스를 상속
public class MyRunnable implements Runnable {
@Override
public void run() {
//실행 코드
}
}Runnable 인터페이스 사용 (권장)
Thread t3 = new Thread(
new Runnable() {
@Override
public void run() {
//실행 코드
}
});
t3.start();익명 클래스
Thread t4 = new Thread(()->{ //실행 코드 });
t4.start();람다식
Thread 주요 메소드
| start() | 쓰레드 시작, run()을 호출함 |
| run() | 쓰레드에서 실행될 코드를 작성하는 메소드 |
| sleep(long millis) | 실행 중인 쓰레드는 밀리초 동안 일시 정지 (알람 맞추고 쉬기) |
| join() | 다른 쓰레드가 종료될 때까지 현재 쓰레드 대기 |
Thread 상태
생성
new
준비
runnable, 큐에 담겨 있음
실행
run
대기
wait, sleep, 큐에 담겨 있음
종료
terminated
Thread 동기화
공유 데이터 동시 접근의 해결책
공유 데이터에 접근하는 모든 스레드를 한 줄로 세우고
한 쓰레드가 공유 데이터에 대한 작업을 끝낼 때까지 다른 쓰레드는 대기
synchronized로 동기화 영역 지정

Lab#3
public class Player1 extends Thread{
String name;
String sound;
int time;
public Player1(String name, String sound,int time) {
this.name = name;
this.sound = sound;
this.time = time;
}
public void run() {
int i = 0;
while(true) {
if(i==time)break;
System.out.println((i+1 )+name +sound);
i++;
}
System.out.println(name + "끝!");
}
}public class Player2 implements Runnable{
String name;
String sound;
int time;
public Player2(String name, String sound,int time) {
this.name = name;
this.sound = sound;
this.time = time;
}
public void run() {
int i = 0;
while(true) {
if(i==time)break;
System.out.println((i+1 )+name +sound);
i++;
}
System.out.println(name + "끝!");
}
}
public class Main {
public static void main(String[] args) {
Thread p1 = new Player1("짱구 ","신난다 신난다 ", 10);
Thread p2 = new Thread(new Player2("맹구 ","훌쩍~ ", 10));
System.out.println(p1.getName());
System.out.println(p2.getName());
p1.start();
p2.start();
}
}누가 먼저 될 지 아무도 모른다
Lab#5
public class BankAccount {
int balance;
public synchronized void deposit(int amount) { //synchronized 붙여줘야함
this.balance += amount;
}
public synchronized void withdraw(int amount) { //synchronized 붙여줘야함
this.balance -= amount;
}
public synchronized int getBalance() { //synchronized 붙여줘야함
System.out.println("잔고: "+this.balance);
return this.balance;
}
}public class User implements Runnable{
BankAccount account;
public User(BankAccount account) {
this.account = account;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
account.deposit(10000);
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
account.withdraw(10000);
if (account.getBalance() < 0) {
System.out.println("오류발생");
}
}
}
}public class Main {
static BankAccount account = new BankAccount();
public static void main(String[] args) {
Thread one = new Thread(new User(account));
Thread two = new Thread(new User(account));
one.start();
two.start();
}
}synchronized의 중요성
Lab#6

Ver2
public class BankAccount {
private int balance = 0;
private int depositAll=0; //예금 금액 합
private int withdrawAll=0; //인출 금액 합
private boolean empty = true; //while문에 필요
// synchronized 메서드: 예금 처리
public synchronized void deposit(int amount) {
while(!empty) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
balance += amount;
depositAll +=amount;
System.out.println("$$ 예금: " + amount + "원 → 현재 잔액: " + balance + "원");
empty=false; //돈 넣고 기다려야 해서
notifyAll(); //돈 넣었다고 알려
}
// synchronized 메서드: 인출 처리
public synchronized void withdraw(int amount) {
while (empty) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (balance >= amount) {
balance -= amount;
withdrawAll +=amount;
System.out.println("-- 인출: " + amount + "원 → 현재 잔액: " + balance + "원");
} else {
// 잔액 부족 시 예외 메시지 출력
System.out.println("!! 인출 실패: 잔액 부족 (" + balance + "원)");
}
empty=true;
notifyAll(); //돈 없다고 알려
}
// 잔액 조회 (동기화 필요 없음)
public int getBalance() {
System.out.println("total 저축금액 : " + depositAll);
System.out.println("total 인출금액 : " + withdrawAll);
return balance;
}
}public class Depositor extends Thread{
private final BankAccount account;
public Depositor(BankAccount account) {
this.account = account;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
account.deposit(1000); // 1,000원 예금
try {
Thread.sleep(500); // 0.5초 대기 후 다음 예금
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}public class Withdrawer extends Thread{
private final BankAccount account;
public Withdrawer(BankAccount account) {
this.account = account;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
account.withdraw(1500);
try {
Thread.sleep(800); // 0.8초 대기 후 다음 인출
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}public class Main {
// 메인 메서드: 쓰레드 실행 및 종료 대기
public static void main(String[] args){
BankAccount account = new BankAccount(); // 계좌 생성
Thread depositor = new Depositor(account); // 예금자 쓰레드
Thread withdrawer = new Withdrawer(account); // 인출자 쓰레드
depositor.start(); // 예금자 실행
withdrawer.start(); // 인출자 실행
try {
depositor.join(); // 예금자 종료까지 대기
withdrawer.join(); // 인출자 종료까지 대기
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 모든 거래 종료 후 최종 잔액 출력
System.out.println(" 거래 종료 → 최종 잔액: " + account.getBalance() + "원");
}
}Thread 동기화의 중요성
Lab#7
public class piglet extends Thread{
private final String name;
int time;
public piglet(String name) {
this.name = name;
this.time = (int)(Math.random()*7000)+3000; //3~10초
}
@Override
public void run() {
System.out.println(name + ": 밖에서 놀다 올께요~ " + (time/1000) + "초 동안 놀거에요!");
try {
Thread.sleep(time); //노는 시간 동안 대기
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(name + ": 집 앞에 도착했어요!");
}
}public class Main {
public static void main(String[] args) {
piglet pig1 = new piglet("첫째 돼지");
piglet pig2 = new piglet("둘째 돼지");
piglet pig3 = new piglet("셋째 돼지");
pig1.start();
pig2.start();
pig3.start();
try { //모두 집에 올 때까지 대기
pig1.join();
pig2.join();
pig3.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("모든 돼지 집 도착");
}
}join()은 이렇게 쓰는 거
Lab#8

public class princess extends Thread{
private Object lock;
public princess(Object lock) {
this.lock = lock;
}
public void run() {
synchronized (lock) { //동기화로 묶어줘야 wait같은 걸 쓸 수 있음
try {
System.out.println("공주 자는 중");
lock.wait();
System.out.println("왕자의 키스로 공주 깨어남");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}public class prince extends Thread{
private Object lock; //타겟 대신에 쓰는 친구인가 봄
public prince(Object lock) {
this.lock=lock;
}
public void kissPrincess(Object lock) {
synchronized (lock) {
System.out.println("왕자 키스로 공주를 깨운다");
lock.notify(); //공주 깨우기
}
}
public void run() {
try {
Thread.sleep(3000); //왕자 등장까지 3초 대기
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
kissPrincess(lock);
}
}public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Object lock = new Object();
Thread princess = new princess(lock);
Thread prince = new prince(lock);
princess.start();
prince.start();
}
}Lock으로 상태 제어
Lab#9~10
public class Buffer {
private int data;
private boolean empty = true;
public synchronized int get() {
while(empty) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
empty = true;
notifyAll();
return data;
}
public synchronized void put(int d) {
while(!empty) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
empty = false;
this.data = d;
notifyAll();
}
}상태 제어 매우 중요
public class Producer extends Thread{
private Buffer buffer;
private int data;
public Producer(Buffer buffer) {
this.buffer = buffer;
}
public void run() {
for (int i = 0; i < 10; i++) {
data = i;
System.out.println("생산자: "+data+"번 빵을 생산");
buffer.put(data);
try {
this.sleep((int)(Math.random()*100));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}public class Consumer extends Thread{
private Buffer buffer;
private int data;
public Consumer(Buffer buffer) {
this.buffer = buffer;
}
public void run() {
for (int i = 0; i < 10; i++) {
data = buffer.get();
System.out.println("소비자: "+data+"번 빵을 소비");
try {
this.sleep((int)(Math.random()*100));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Buffer b = new Buffer();
Producer t1 = new Producer(b);
Consumer t2 = new Consumer(b);
t1.start();
t2.start();
}
}
'JAVA' 카테고리의 다른 글
| [JAVA] 디자인 패턴 - 템플릿 메소드 (0) | 2025.10.17 |
|---|---|
| [JAVA] 디자인 패턴 - 전략 (짱구 예제) (0) | 2025.10.15 |
| [JAVA] 커피메이커 Ver.1 (3) | 2025.10.01 |
| [JAVA] Generic & Collection (0) | 2025.09.19 |
| [Refactoring] Battle_상속,모듈화 문제 (JAVA) (0) | 2025.09.16 |