Notice
Recent Posts
Recent Comments
Link
개발 무지렁이
[Java] 공유객체 내부데이터에 대한 스레드 동기화와 정확한 작업교대 본문
𐁍 스레드 동기화
멀티스레드는 공유객체에 서로 접근할 수 있다.
다른 스레드에 의해 공유객체의 내부데이터가 쉽게 변경되기 때문에,
하나의 스레드가 접근할 때, 다른 스레드가 접근하지 못하도록
작업이 끝날 때까지 객체에 잠금(Lock🔒)을 걸어야 한다.
(그렇지 않으면 의도치 않은 결과가 나올 수 있다.)
이를 위해, 자바는 동기화 메서드 및 동기화 블록을 제공한다.
다른 스레드에 의해 공유객체의 내부데이터가 쉽게 변경되기 때문에,
하나의 스레드가 접근할 때, 다른 스레드가 접근하지 못하도록
작업이 끝날 때까지 객체에 잠금(Lock🔒)을 걸어야 한다.
(그렇지 않으면 의도치 않은 결과가 나올 수 있다.)
이를 위해, 자바는 동기화 메서드 및 동기화 블록을 제공한다.
➼ 🦔 동기화 메서드 및 동기화 블록
⚠️ 공유객체 내부에 동기화 메서드 및 동기화 블록을 정의해 놓는다.
🕹️ 동기화 메서드
(동기화 메서드를 실행하는 즉시, 🔒객체잠금이 일어나고, 실행이 끝나면 잠금이 풀린다.)
🕹️ 동기화 메서드
(동기화 메서드를 실행하는 즉시, 🔒객체잠금이 일어나고, 실행이 끝나면 잠금이 풀린다.)
public synchronized void method() {
//하나의 스레드만 실행할 수 있는 영역
}
🍫 동기화 블록
(일부 코드영역을 실행할 때만 🔒객체잠금을 걸고 싶다면, 동기화 블록을 만들면 된다.)
synchronized([공유객체]) {
//하나의 스레드만 실행할 수 있는 영역
}
📜 Calculator.java
//🎃 공유객체
public class Calculator {
private int memory;
public int getMemory() {
return memory;
}
//🕹️ 동기화 메서드
public synchronized void setMemory1(int memory) {
this.memory = memory;
try {
Thread.sleep(2000);
} catch (InterruptedException e) { }
System.out.println(Thread.currentThread().getName() + ": " + this.memory);
}
public void setMemory2(int memory) {
//🍫 동기화 블록
synchronized(this) {
this.memory = memory;
try {
Thread.sleep(2000);
} catch (InterruptedException e) { }
System.out.println(Thread.currentThread().getName() + ": " + this.memory);
}
}
}
📜 User1Thread.java
//🪡 스레드1
public class User1Thread extends Thread {
private Calculator calculator;
public User1Thread() {
setName("User1Thread");
}
//🎃 공유객체 초기화
public void setCalculator(Calculator calculator) {
this.calculator = calculator;
}
@Override
public void run() {
calculator.setMemory1(100);
}
}
📜 User2Thread.java
//🪡 스레드2
public class User2Thread extends Thread {
private Calculator calculator;
public User2Thread() {
setName("User2Thread");
}
//🎃 공유객체 초기화
public void setCalculator(Calculator calculator) {
this.calculator = calculator;
}
@Override
public void run() {
calculator.setMemory2(50);
}
}
📜 SynchronizedExample.java
public class SynchronizedExample {
public static void main(String[] args) {
//🎃 공유객체 생성
Calculator calculator = new Calculator();
//🪡 스레드1 생성, 공유객체 지정, 작업 실행
User1Thread user1Thread = new User1Thread();
user1Thread.setCalculator(calculator);
user1Thread.start();
//🪡 스레드2 생성, 공유객체 지정, 작업 실행
User2Thread user2Thread = new User2Thread();
user2Thread.setCalculator(calculator);
user2Thread.start();
//User1Thread: 100
//User2Thread: 50
}
}
⭐ 스레드 동기화 원리
user1Thread.start()를 통해 run() 메서드를 실행하고,
동기화 메서드 setMemory1()을 실행하는 순간 Calculator 객체를 잠근다.🔒
user1Thread.start()를 통해 run() 메서드를 실행하고,
동기화 메서드 setMemory1()을 실행하는 순간 Calculator 객체를 잠근다.🔒
𖠃 정확한 교대작업 (두개의 스레드를 교대로 번갈아가며 실행)
⚠️ 공유객체는 두 스레드가 작업할 내용을 각각 동기화 메서드로 정의해 놓는다.
⚠️ wait()와 notify(), notifyAll()은 동기화 메서드 or 동기화 블록 내에서만 사용할 수 있다.
⚠️ wait()와 notify(), notifyAll()은 동기화 메서드 or 동기화 블록 내에서만 사용할 수 있다.
📜 WorkObject.java
// 🎃 공유객체
public class WorkObject {
//🕹️ 동기화 메서드
public synchronized void methodA() {
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + ": methodA 작업 실행");
notify(); //다른 스레드를 SUSPENDED -> RUNNABLE
try {
wait(); //자신 스레드를 SUSPENDED
} catch(InterruptedException e) { }
}
//🕹️ 동기화 메서드
public synchronized void methodB() {
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + ": methodB 작업 실행");
notify();
try {
wait();
} catch(InterruptedException e) { }
}
}
📜 ThreadA.java
//🪡 스레드A
public class ThreadA extends Thread {
private WorkObject workObject;
public ThreadA(WorkObject workObject) {
setName("ThreadA");
this.workObject = workObject;
}
@Override
public void run() {
for(int i = 0; i < 10; i++) {
workObject.methodA();
}
}
}
📜 ThreadB.java
//🪡 스레드B
public class ThreadB extends Thread {
private WorkObject workObject;
public ThreadB(WorkObject workObject) {
setName("ThreadB");
this.workObject = workObject;
}
@Override
public void run() {
for(int i = 0; i < 10; i++) {
workObject.methodB();
}
}
}
📜 WaitNotifyExample.java
public class WaitNotifyExample {
public static void main(String[] args) {
//🎃 공유객체 생성
WorkObject workObject = new WorkObject();
//🪡 스레드 A,B 생성
ThreadA threadA = new ThreadA();
ThreadB threadB = new ThreadB();
//🪡 각각의 스레드 작업 실행
threadA.start();
threadB.start();
//ThreadA: methodA 작업 실행
//ThreadB: methodB 작업 실행
//ThreadA: methodA 작업 실행
//ThreadB: methodB 작업 실행
//...
}
}
'Backend > 자바' 카테고리의 다른 글
[Java] 보조 역할을 수행하는 데몬(Daemon) 스레드 (0) | 2023.08.13 |
---|---|
[Java] 스레드 정상 실행 종료, interrupt( ): 리소스 정리 후 실행 종료 (0) | 2023.08.13 |
[Java] CPU스케쥴링에 따른 스레드(Thread) 상태와 상태 이동 메서드 (0) | 2023.08.12 |
[Java] 하나의 프로세스 안의 멀티스레드(메인스레드 + 多 작업스레드)의 구현 (0) | 2023.08.12 |
[Java] 타입파라미터를 가지는 제네릭 타입 및 제네릭 메서드 (0) | 2023.08.12 |
Comments