๐ Process vs Thread
- ํ๋ก์ธ์ค : ์ด์์ฒด์ ๋ก ๋ถํฐ ์์์ ํ ๋น๋ฐ๋ ์์ ์ ๋จ์
- ์ฐ๋ ๋ : ํ๋ก์ธ์ค๊ฐ ํ ๋น๋ฐ์ ์์์ ์ด์ฉํ๋ ์คํ์ ๋จ์

์ฆ, ํ๋ ํ๋ ํฌ๊ฒ ๋ด์ ํ๋ก๊ทธ๋จ๋ค์ ํ๋ก์ธ์ค๋ผ๊ณ ํ๊ณ , ๊ทธ ์์ ์คํ๋๋ ๊ฒ๋ค์ ์ฐ๋ ๋๋ผ๊ณ ํฉ๋๋ค.
๐ OS๊ฐ ํ๋ก๊ทธ๋จ ์คํ์ ์ํ ํ๋ก์ธ์ค๋ฅผ ํ ๋น ํด์ค๋ ํ๋ก์ธ์ค ์์ ํ๋ก๊ทธ๋จ Code์ Data ๊ทธ๋ฆฌ๊ณ Memory Area(Stack, Heap)์ ํจ๊ป ํ ๋นํด์ค๋๋ค.
Code๋ Java main ๊ณผ ๊ฐ์ ์ฝ๋๋ฅผ ๋งํฉ๋๋ค.
Data๋ ํ๋ก๊ทธ๋จ์ด ์คํ ์ค ์ ์ฅํ ์ ์๋ ์ ์ฅ๊ณต๊ฐ์ ๋งํฉ๋๋ค.
- ์ ์ญ, ์ ์ , ๋ฐฐ์ด ๋ฑ ์ด๊ธฐํ๋ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ๊ณต๊ฐ
Memory Area
- Stack : ์ง์ญ๋ณ์, ๋งค๊ฐ๋ณ์ ๋ฆฌํด ๋ณ์๋ฅผ ์ ์ฅํ๋ ๊ณต๊ฐ
- Heap : ํ๋ก๊ทธ๋จ์ด ๋์ ์ผ๋ก ํ์ํ ๋ณ์๋ฅผ ์ ์ฅํ๋ ๊ณต๊ฐ(new(), mallok())

: ์ฐ๋ ๋๋ ํ๋ก์ธ์ค ๋ด์์ ์ผํ๋ ์ผ๊พผ์ผ๋ก, ์ฝ๋ ์คํ์ ํ๋ฆ์ด๋ผ๊ณ ์๊ฐํ ์ ์์ต๋๋ค.

๐ ์ผ๋ฐ ์ฐ๋ ๋์ ๋์ผํ๋ฉฐ JVM ํ๋ก์ธ์ค ์์์ ์คํ๋๋ ์ฐ๋ ๋๋ฅผ Java Thread๋ผ๊ณ ํฉ๋๋ค.

Java๋ ๋ฉ์ธ ์ฐ๋ ๋๊ฐ Main() ๋ฉ์๋๋ฅผ ์คํ์ํค๋ฉด์ ์์์ด ๋ฉ๋๋ค.
๐ ํ๋ก์ธ์ค ์์์ ํ๋์ ์ฐ๋ ๋๋ง ์คํ๋๋ ๊ฒ์ ๋งํฉ๋๋ค.
main() ๋ฉ์๋๋ง ์คํ์์ผฐ์ ๋ Single Thread๋ผ๊ณ ํฉ๋๋ค.public class Main {
public static void main(String[] args) {
Runnable task = () -> {
System.out.print("2๋ฒ -> " + Thread.currentThread().getName());
for (int i = 0; i < 100; i++) {
System.out.print("$");
}
};
System.out.print("1๋ฒ -> " + Thread.currentThread().getName());
Thread thread1 = new Thread(task);
thread1.setName("thread1");
thread1.start();
}
}์์ ์ฝ๋๋ฅผ ๋ถ์ํ๋ฉด, 1๋ฒ์ main ์ฐ๋ ๋๊ฐ ๋จผ์ ์คํ๋๊ณ , ๊ทธ์ ๋ฐ๋ผ Thread1 ์ด ์คํ๋๋ ๊ฒฐ๊ณผ๋ฅผ ํ์ธ ํ ์ ์์ต๋๋ค.
๐ ํ๋ก์ธ์ค ์์์ ์ฌ๋ฌ๊ฐ์ ์ฐ๋ ๋๊ฐ ์คํ๋๋ ๊ฒ์ ๋งํฉ๋๋ค.
Runnable task = () -> {
for (int i = 0; i < 100; i++) {
System.out.print("$");
}
};
Runnable task2 = () -> {
for (int i = 0; i < 100; i++) {
System.out.print("*");
}
};
Thread thread1 = new Thread(task);
thread1.setName("thread1");
Thread thread2 = new Thread(task2);
thread2.setName("thread2");
thread1.start();
thread2.start();
}public class Main{
public static void main(String args[]){
// ์ด๋ฐ์์ผ๋ก Thread๋ฅผ extendsํ ํด๋์ค๋ฅผ ์ธ์คํด์คํ ์์ผ์ ๋ด๋ถ์
// `run()`์ ๊ตฌํํ ๋์์ ์คํ ์ํต๋๋ค.
TestThread thread = new TestThread();
thread.start();
}
}public class Main{
public static void main(String args[]){
// ์ด๋ฐ์์ผ๋ก Runnable๋ฅผ implementsํ ํด๋์ค๋ฅผ ์ธ์คํด์คํ ์์ผ์ ๋ด๋ถ์
// `run()`์ ๊ตฌํํ ๋์์ ์คํ ์ํต๋๋ค.
Runnable thread = new TestRunnable();
thread.start();
}
}public class Main{
public static void main(String args[]){
// ์ด๋ฐ์์ผ๋ก Runnable๋ฅผ implementsํ ํด๋์ค๋ฅผ ์ธ์คํด์คํ ์์ผ์ ๋ด๋ถ์
// `run()`์ ๊ตฌํํ ๋์์ ์คํ ์ํต๋๋ค.
Runnable task = () -> {
int sum = 0;
for(int i = 0; i < 50; i++){
sum+=i;
System.out.println(sum);
}
System.out.println(Thread.currentThread().getName() + " ์ต์ข
ํฉ : " + sum);
}
}
} ๋ง์ง๋ง์ lambda ์ ๋ฐฉ์์ผ๋ก ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ์ด๋ฌํ ๋ฐฉ์์ ๋ํด์ ์ต์ํด์ง ํ์๊ฐ ์์ต๋๋ค. ์ด๋ฌํ, task๋ฅผ ๋์์ ์ฌ๋ฌ๊ฐ์ Thread์ ์คํด์ ํ๊ฒ ๋๋ฉด ์ถ๋ ฅ ๊ฐ์ด ์์ฌ์ ๋์ค๋ ๊ฒ์ ํ์ธ ํ ์ ์์ต๋๋ค.๐ ๋ณด์ด์ง ์๋๊ณณ(background)์์ ์คํด์ค๋๋ ๋ฎ์ ์ฐ์ ์์๋ฅผ ๊ฐ์ง ์ฐ๋ ๋๋ฅผ ๋งํฉ๋๋ค.
public class Main {
public static void main(String[] args) {
Runnable demon = () -> {
for (int i = 0; i < 1000000; i++) {
System.out.println("demon");
}
};
// ๋ค๋ฅธ ์ฐ๋ ๋์ ๋นํด ๋ฆฌ์์ค๋ฅผ ์ ๊ฒ ํ ๋น ๋ฐ๊ธฐ ๋๋ฌธ์ ์๋์ ์ผ๋ก ๋๋ฆฌ๊ฒ ์คํ์ด ๋ฉ๋๋ค.
Thread thread = new Thread(demon);
thread.setDaemon(true); // true๋ก ์ค์ ์ ๋ฐ๋ชฌ์ค๋ ๋๋ก ์คํ๋จ
thread.start();
for (int i = 0; i < 100; i++) {
System.out.println("task");
}
}
}์ด๋ฐ, Demon Thread๋ ์ฐ๋ ๋๊ฐ ๋ค ๋๋ ๋ ๊น์ง ๊ธฐ๋ค๋ ค์ง๋ ๊ฒ์ด ์๋๋ผ ์ด๋์ ๋ ์๊ฐ์ด ์ง๋๋ฉด ๋๋๊ฒ ๋ฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ , ์ด๋ ๊ฒ Demon Thread๋ฅผ ์ ์ธํ ์ฐ๋ฆฌ๊ฐ ๋ง๋ ์ฐ๋ ๋๋ค์ User Thread ๋ผ๊ณ ํฉ๋๋ค.
๐ ์ฐ๋ ๋ ์์ ์ ์ค์๋์ ๋ฐ๋ผ์ ์ฐ๋ ๋์ ์ฐ์ ์์๋ฅผ ๋ถ์ฌํ ์ ์์ต๋๋ค.
์์ ์ฐ์ ์์๋ฅผ ์ฃผ์ด์, ์์ ์๊ฐ์ ํ ๋นํด ๊ธํ ๊ฒ์ ๋จผ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ ํ ์ ์์ต๋๋ค.
- ์ฐ์ ์์๋ ์๋์ ๊ฐ์ด 3๊ฐ์ง๋ก ๋๋ฉ๋๋ค.
- MAX_PRIORITY = 10
- MIN_PRIORITY = 1
- NROM_PRIORITY = 5
- ๊ธฐ๋ณธ ๊ฐ์ด ๋ณดํต ์ฐ์ ์์ ์
๋๋ค.
- ์ด ์ฐ์ ์์์ ๋ฒ์๋ OS๊ฐ ์๋๋ผ JVM์์ ์ค์ ํ ์ฐ์ ์์์
๋๋ค.
Thread thread1 = new Thread();
thread1.setPriority(8);
public class Main {
public static void main(String[] args) {
Runnable task = () -> {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
break;
}
}
System.out.println(Thread.currentThread().getName() + " Interrupted");
};
// ThreadGroup ํด๋์ค๋ก ๊ฐ์ฒด๋ฅผ ๋ง๋ญ๋๋ค.
ThreadGroup group1 = new ThreadGroup("Group1");
// Thread ๊ฐ์ฒด ์์ฑ์ ์ฒซ๋ฒ์งธ ๋งค๊ฐ๋ณ์๋ก ๋ฃ์ด์ค๋๋ค.
// Thread(ThreadGroup group, Runnable target, String name)
Thread thread1 = new Thread(group1, task, "Thread 1");
Thread thread2 = new Thread(group1, task, "Thread 2");
// Thread์ ThreadGroup ์ด ํ ๋น๋๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
System.out.println("Group of thread1 : " + thread1.getThreadGroup().getName());
System.out.println("Group of thread2 : " + thread2.getThreadGroup().getName());
thread1.start();
thread2.start();
try {
// ํ์ฌ ์ฐ๋ ๋๋ฅผ ์ง์ ๋ ์๊ฐ๋์ ๋ฉ์ถ๊ฒ ํฉ๋๋ค.
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// interrupt()๋ ์ผ์์ ์ง ์ํ์ธ ์ฐ๋ ๋๋ฅผ ์คํ๋๊ธฐ ์ํ๋ก ๋ง๋ญ๋๋ค.
group1.interrupt();
}
}๐ ์ฐ๋ฆฌ๋ ๋์์์ ๋ณด๊ฑฐ๋ ์์ ์ ๋ฃ๊ณ ์์ ๋ ์ผ์์ ์ง ํ์ ๋ค์ ๋ณด๊ฑฐ๋ ๋ฃ๊ธฐ๋ ํ๊ณ ์ค๊ฐ์ ์ข ๋ฃ ์ํค๊ธฐ๋ ํฉ๋๋ค. ์ฐ๋ ๋๋ ๋ง์ฐฌ๊ฐ์ง๋ก ์ํ๊ฐ ์กด์ฌํ๊ณ ์ด๋ฅผ ์ ์ด๋ฅผ ํ ์ ์์ต๋๋ค.
run() ๋ฉ์๋๋ฅผ ์ํํฉ๋๋ค.run() method๋ ๋ํ ์ข
๋ฃ๋ฉ๋๋ค.

๐ ์๋๋ ์ฐ๋ ๋์ ์ํ๋ฅผ ์ ๋ฆฌํ ํ์ ๋๋ค.
์ํ Enum ์ค๋ช ๊ฐ์ฒด์์ฑ NEW ์ฐ๋ ๋ ๊ฐ์ฒด ์์ฑ, ์์ง start() ๋ฉ์๋ ํธ์ถ ์ ์ ์ํ ์คํ๋๊ธฐ RUNNABLE ์คํ ์ํ๋ก ์ธ์ ๋ ์ง ๊ฐ ์ ์๋ ์ํ ์ผ์์ ์ง WAITING ๋ค๋ฅธ ์ฐ๋ ๋๊ฐ ํต์ง(notify) ํ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๋ ์ํ ์ผ์์ ์ง TIMED_WAITING ์ฃผ์ด์ง ์๊ฐ ๋์ ๊ธฐ๋ค๋ฆฌ๋ ์ํ ์ผ์์ ์ง BLOCKED ์ฌ์ฉํ๊ณ ์ ํ๋ ๊ฐ์ฒด์ Lock์ด ํ๋ฆด ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๋ ์ํ ์ข ๋ฃ TERMINATED ์ฐ๋ ๋์ ์์ ์ด ์ข ๋ฃ๋ ์ํ

sleep() : ํ์ฌ ์ฐ๋ ๋๋ฅผ ์ง์ ๋ ์๊ฐ๋์ ๋ฉ์ถ๊ฒ ํฉ๋๋ค. - TIMED-WAITING
public class Main {
public static void main(String[] args) {
Runnable task = () -> {
try {
// (1) ์์ธ์ฒ๋ฆฌ ํ์!
// - interrunpt() ๋ฅผ ๋ง๋๋ฉด ๋ค์ ์คํ๋๊ธฐ ๋๋ฌธ์
// - interruptedException์ด ๋ฐ์ํ ์ ์๋ค.
// (2) ํน์ ์ฐ๋ ๋ ์ง๋ชฉ ๋ถ๊ฐ
Thread.sleep(2000); // TIMED_WAITING
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task : " + Thread.currentThread().getName());
};
Thread thread = new Thread(task, "Thread");
thread.start();
try {
// 1์ด๊ฐ ์ง๋๊ณ ๋๋ฉด runnable ์ํ๋ก ๋ณํ์ฌ ๋ค์ ์คํ๋ฉ๋๋ค.
// ํน์ ์ค๋ ๋๋ฅผ ์ง๋ชฉํด์ ๋ฉ์ถ๊ฒ ํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํฉ๋๋ค.
//
thread.sleep(1000); // static method์ด๊ธฐ ๋๋ฌธ์ main thread์ ๊ฐ์ ๋์์ ํฉ๋๋ค.
System.out.println("sleep(1000) : " + Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Thread.sleep() ๋ฉ์๋ ์์ฒด๊ฐ static์ผ๋ก ์ ์ธ์ด ๋์ด ์๊ธฐ ๋๋ฌธ์ ํน์ ๋ถ๋ถ์ ๋ํด์ sleep์ ํ๋ ๊ฒ์ด ์๋๋ผ, ์ฐ๋ ๋ ์์ฒด์ ์๊ฐ์ ์ผ์ ์
๋ ฅํ ์๊ฐ๋์ ๋ฉ์ถ๊ฒ ํ๋ ๊ฒ์์ ์ ์ ์์ต๋๋ค. ๋ํ try-catch ๋ก ๊ฐ์ธ์ค ์ด์ ๋ ํด๋น sleep() ๋ฉ์๋๋ throws InterruptedException์ ๋ฐํํ์ฌ ์ํํ ๋ฉ์๋์์ ์๋ ค์ฃผ๊ณ ์๊ธฐ ๋๋ฌธ์ ๊ฐ์ธ์ฃผ๊ณ ์๋ ๊ฒ์
๋๋ค.
Interrupt() : ์ผ์์ ์ง ์ํ์ธ ์ฐ๋ ๋๋ฅผ ์คํ๋๊ธฐ ์ํ๋ก ๋ง๋ญ๋๋ค.
public class Main {
public static void main(String[] args) {
Runnable task = () -> {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task : " + Thread.currentThread().getName());
};
Thread thread = new Thread(task, "Thread");
thread.start(); // NEW -> Runnable๋ก ๊ฐ์ ์คํ์ด ๋ฉ๋๋ค.
thread.interrupt(); // ์ค๋ ๋๋ฅผ ์คํ๋๊ธฐ ์ํ๋ฅผ ๋ฐฉํดํ๊ณ catch๋ฌธ์ผ๋ก ๋น ์ง๊ฒ ๋ง๋ญ๋๋ค.
System.out.println("thread.isInterrupted() = " + thread.isInterrupted());
}
}
public class Main {
public static void main(String[] args) {
Runnable task = () -> {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
break;
}
}
System.out.println("task : " + Thread.currentThread().getName());
};
Thread thread = new Thread(task, "Thread");
thread.start();
thread.interrupt();
System.out.println("thread.isInterrupted() = " + thread.isInterrupted());
}
}
Join()
๐ ์ ํด์ง ์๊ฐ ๋์ ์ง์ ํ ์ฐ๋ ๋๊ฐ ์์ ํ๋ ๊ฒ์ ๊ธฐ๋ค๋ฆฝ๋๋ค.
- ์๊ฐ์ ์ง์ ํ์ง ์์์ ๋๋ ์ง์ ํ ์ฐ๋ ๋์ ์์ ์ด ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค.
join() ์ฌ์ฉ๋ฐฉ๋ฒThread thread = new Thread(task, "thread");
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}Thread.sleep(ms); ms(๋ฐ๋ฆฌ์ด) ๋จ์๋ก ์ค์ ๋ฉ๋๋ค.
์์ธ ์ฒ๋ฆฌ๋ฅผ ํด์ผ ํฉ๋๋ค.
**interrupt() ๋ฅผ ๋ง๋๋ฉด ๊ธฐ๋ค๋ฆฌ๋ ๊ฒ์ ๋ฉ์ถ๊ธฐ ๋๋ฌธ์ InterruptedException์ด ๋ฐ์ํ ์ ์์ต๋๋ค.**์๊ฐ์ ๋ฐ๋ก ์ง์ ํ์ง ์์๊ธฐ ๋๋ฌธ์ thread๊ฐ ์์ ์ด ๋๋ ๋๊น์ง main ์ฐ๋ ๋๋ ๊ธฐ๋ค๋ฆฌ๊ฒ ๋ฉ๋๋ค.
public class Main {
public static void main(String[] args) {
Runnable task = () -> {
try {
Thread.sleep(5000); // 5์ด
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Thread thread = new Thread(task, "thread");
thread.start();
long start = System.currentTimeMillis();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// thread ์ ์์์๊ฐ์ธ 5000ms ๋์ main ์ฐ๋ ๋๊ฐ ๊ธฐ๋ค๋ ธ๊ธฐ ๋๋ฌธ์ 5000์ด์์ด ์ถ๋ ฅ๋ฉ๋๋ค.
System.out.println("์์์๊ฐ = " + (System.currentTimeMillis() - start));
}
}
๐ ๋จ์ ์๊ฐ์ ๋ค์ ์ฐ๋ ๋์๊ฒ ์๋ณดํ๊ณ ์ฐ๋ ๋ ์์ ์ ์คํ ๋๊ธฐ ์ํ๊ฐ ๋ฉ๋๋ค.
yield() ์ฌ์ฉ๋ฐฉ๋ฒ
public class Main {
public static void main(String[] args) {
Runnable task = () -> {
try {
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName());
}
} catch (InterruptedException e) {
Thread.yield(); // thread1์ resource๊ฐ 5์ด๋ค์ thread2๋ก ์๋๋ฉ๋๋ค.
}
};
Thread thread1 = new Thread(task, "thread1");
Thread thread2 = new Thread(task, "thread2");
thread1.start();
thread2.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread1.interrupt(); // ์คํ๋๊ธฐ ์ํ๋ก ๋ง๋ ๋ค.
}
}
Thread.yield() ์ด ์คํ๋์ด thread1์ ์คํ ๋๊ธฐ ์ํ๋ก ๋ณ๊ฒฝ๋๋ฉด์ ๋จ์ ์๊ฐ์ thread2์๊ฒ ๋ฆฌ์์ค๊ฐ ์๋ณด๋ฉ๋๋ค.public class Main {
public static void main(String[] args) {
Runnable task = () -> {
try {
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName());
}
} catch (InterruptedException e) {
Thread.yield();
}
};
Thread thread1 = new Thread(task, "thread1");
Thread thread2 = new Thread(task, "thread2");
thread1.start();
thread2.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread1.interrupt();
}
}
๐ ๋ฉํฐ ์ฐ๋ ๋์ ๊ฒฝ์ฐ ์ฌ๋ฌ ์ฐ๋ ๋๊ฐ ํ ํ๋ก์ธ์ค์ ์์์ ๊ณต์ ํด์ ์์ ํ๊ธฐ ๋๋ฌธ์ ์๋ก์๊ฒ ์ํฅ์ ์ค ์ ์์ต๋๋ค. ์ด๋ก ์ธํด์ ์ฅ์ ๋ ๋ฒ๊ทธ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
- ์ด๋ฌํ ์ผ์ ๋ฐฉ์งํ๊ธฐ ์ํด(์์์ ๊ณต์ ํ๋ค๊ฐ ์๊ธธ ์ ์๋ ์ค๋ฅ) ํ ์ฐ๋ ๋๊ฐ ์งํ์ค์ธ ์์ ์ ๋ค๋ฅธ ์ฐ๋ ๋๊ฐ ์นจ๋ฒํ์ง ๋ชปํ๋๋ก ๋ง๋ ๊ฒ์
Thread Synchronized๋ผ๊ณ ํฉ๋๋ค.- ๋๊ธฐํ๋ฅผ ํ๋ ค๋ฉด ๋ค๋ฅธ ์ฐ๋ ๋์ ์นจ๋ฒ์ ๋ง์์ผ ํ๋ ์ฝ๋๋ค์
์๊ณ ์์ญ์ผ๋ก ์ค์ ํ๋ฉด ๋ฉ๋๋ค.
synchronized ๋ฅผ ์ฌ์ฉํ ๋๊ธฐํ public synchronized void asyncSum() {
...์นจ๋ฒ์ ๋ง์์ผํ๋ ์ฝ๋...
}
synchronized(ํด๋น ๊ฐ์ฒด์ ์ฐธ์กฐ๋ณ์) {
...์นจ๋ฒ์ ๋ง์์ผํ๋ ์ฝ๋...
}
synchronized ์ฌ์ฉ ๋ฐฉ๋ฒsynchronzied ์์ ๋ ๋จ์ ์ฌ๊ณผ์ ์๊ฐ ๋ค์ฃฝ๋ฐ์ฃฝ ์ถ๋ ฅ๋ ๋ฟ๋ง ์๋๋ผ ์๋ ์ฌ๊ณผ๋ฅผ ๋จน๋ ๊ฒฝ์ฐ๋ ๋ฐ์ํฉ๋๋ค.
public class Main {
public static void main(String[] args) {
AppleStore appleStore = new AppleStore();
Runnable task = () -> {
while (appleStore.getStoredApple() > 0) {
appleStore.eatApple();
System.out.println("๋จ์ ์ฌ๊ณผ์ ์ = " + appleStore.getStoredApple());
}
};
for (int i = 0; i < 3; i++) {
new Thread(task).start();
}
}
}
class AppleStore {
private int storedApple = 10;
public int getStoredApple() {
return storedApple;
}
public void eatApple() {
if (storedApple > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
storedApple -= 1;
}
}
}
```
- `synchronized` ์์ ๋
```java
public class Main {
public static void main(String[] args) {
AppleStore appleStore = new AppleStore();
Runnable task = () -> {
while (appleStore.getStoredApple() > 0) {
appleStore.eatApple();
System.out.println("๋จ์ ์ฌ๊ณผ์ ์ = " + appleStore.getStoredApple());
}
};
for (int i = 0; i < 3; i++) {
new Thread(task).start();
}
}
}
class AppleStore {
private int storedApple = 10;
public int getStoredApple() {
return storedApple;
}
public void eatApple() {
synchronized (this) {
if(storedApple > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
storedApple -= 1;
}
}
}
}
๐ ์นจ๋ฒ์ ๋ง์ ์ฝ๋๋ฅผ ์ํํ๋ค๊ฐ ์์ ์ ๋ ์ด์ ์งํํ ์ํฉ์ด ์๋๋ฉด,
wait()์ ํธ์ถํ์ฌ ์ฐ๋ ๋๊ฐ Lock์ ๋ฐ๋ฉํ๊ณ ๊ธฐ๋ค๋ฆฌ๊ฒ ํ ์ ์์ต๋๋ค.
wait() : ์คํ ์ค์ด๋ ์ฐ๋ ๋๋ ํด๋น ๊ฐ์ฒด์ waiting pool์์ ํต์ง๋ฅผ ๊ธฐ๋ค๋ฆฝ๋๋ค.notify() : ํด๋น ๊ฐ์ฒด์ waiting pool ์ ์๋ ๋ชจ๋ ์ฐ๋ ๋ ์ค์์ ์์์ ์ฐ๋ ๋๋ง ํต์ง๋ฅผ ๋ฐ์ต๋๋ค. public class Main {
public static String[] itemList = {
"MacBook", "IPhone", "AirPods", "iMac", "Mac mini"
};
public static AppleStore appleStore = new AppleStore();
public static final int MAX_ITEM = 5;
public static void main(String[] args) {
// ๊ฐ๊ฒ ์ ์
Runnable StoreClerk = () -> {
while (true) {
// 0 ~ 4๊น์ง ๋๋คํ ์ซ์ ์ถ๋ ฅ
int randomItem = (int) (Math.random() * MAX_ITEM);
// restock ์ ์ ๊ณ ๋ฅผ ๋ฃ๋ ๋ฉ์๋๋ผ๊ณ ํ ์ ์์ต๋๋ค.
appleStore.restock(itemList[randomItem]);
try {
Thread.sleep(50);
} catch (InterruptedException ignored) {
}
}
};
// ๊ณ ๊ฐ
Runnable Customer = () -> {
while (true) {
try {
Thread.sleep(77);
} catch (InterruptedException ignored) {
}
int randomItem = (int) (Math.random() * MAX_ITEM);
appleStore.sale(itemList[randomItem]);
System.out.println(Thread.currentThread().getName() + " Purchase Item " + itemList[randomItem]);
}
};
new Thread(StoreClerk, "StoreClerk").start();
new Thread(Customer, "Customer1").start();
new Thread(Customer, "Customer2").start();
}
}
class AppleStore {
private List<String> inventory = new ArrayList<>();
public void restock(String item) {
synchronized (this) {
while (inventory.size() >= Main.MAX_ITEM) {
System.out.println(Thread.currentThread().getName() + " Waiting!");
try {
wait(); // ์ฌ๊ณ ๊ฐ ๊ฝ ์ฐจ์์ด์ ์ฌ์
๊ณ ํ์ง ์๊ณ ๊ธฐ๋ค๋ฆฌ๋ ์ค!
Thread.sleep(333);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// ์ฌ์
๊ณ
inventory.add(item);
notify(); // ์ฌ์
๊ณ ๋์์์ ๊ณ ๊ฐ์๊ฒ ์๋ ค์ฃผ๊ธฐ
System.out.println("Inventory ํํฉ: " + inventory.toString());
}
}
public synchronized void sale(String itemName) {
while (inventory.size() == 0) {
System.out.println(Thread.currentThread().getName() + " Waiting!");
try {
wait(); // ์ฌ๊ณ ๊ฐ ์๊ธฐ ๋๋ฌธ์ ๊ณ ๊ฐ ๋๊ธฐ์ค
Thread.sleep(333);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
while (true) {
// ๊ณ ๊ฐ์ด ์ฃผ๋ฌธํ ์ ํ์ด ์๋์ง ํ์ธ
for (int i = 0; i < inventory.size(); i++) {
if (itemName.equals(inventory.get(i))) {
inventory.remove(itemName);
notify(); // ์ ํ ํ๋ ํ๋ ธ์ผ๋ ์ฌ์
๊ณ ํ๋ผ๊ณ ์๋ ค์ฃผ๊ธฐ
return; // ๋ฉ์๋ ์ข
๋ฃ
}
}
// ๊ณ ๊ฐ์ด ์ฐพ๋ ์ ํ์ด ์์ ๊ฒฝ์ฐ
try {
System.out.println(Thread.currentThread().getName() + " Waiting!");
wait();
Thread.sleep(333);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
๐ synchronized ๋ธ๋ญ์ผ๋ก ๋๊ธฐํํ๋ฉด ์๋์ ์ผ๋ก lock ์ด ๊ฑธ๋ฆฌ๊ณ ํ๋ฆฌ์ง๋ง, ๊ฐ์ ๋ฉ์๋ ๋ด์์๋ง lock์ ๊ฑธ ์ ์๋ค๋ ์ ์ฝ์ด ์์ต๋๋ค.
์ด๋ฐ ์ ์ฝ์ ํด๊ฒฐ ํ๊ธฐ ์ํด Lock ํด๋์ค๋ฅผ ์ฌ์ฉํฉ๋๋ค.
public class MyClass {
private Object lock1 = new Object();
private Object lock2 = new Object();
public void methodA() {
synchronized (lock1) {
methodB();
}
}
public void methodB() {
synchronized (lock2) {
// do something
methodA();
}
}
}
์ด๋, ํด๋น ๋ฝ์ ์ฌ์ฉํ๋ฉด, ๊ฐ์ ์ค๋ ๋๊ฐ ๊ฐ์ ๋ฝ์ ๊ฐ์ง๊ณ ์์ด๋ ์ ์งํ๋ฉฐ ๊ณ์ ์คํ ํ ์ ์๊ฒ ํฉ๋๋ค.
๐ wait() & notify()์ ๋ฌธ์ ์ ์ธ waiting pool ๋ด ์ฐ๋ ๋๋ฅผ ๊ตฌ๋ถํ์ง ๋ชปํ๋ค๋ ๊ฒ์ ํด๊ฒฐํ ๊ฒ์ด Condition์ ๋๋ค.
[์ถ๊ฐ ์ค๋ช ]
wait()๊ณผ notify()๋ ๊ฐ์ฒด์ ๋ํ ๋ชจ๋ํฐ๋ง ๋ฝ(lock)์ ์ด์ฉํ์ฌ ์ค๋ ๋๋ฅผ ๋๊ธฐ์ํค๊ณ ๊นจ์๋๋ค. ๊ทธ๋ฌ๋ wait()๊ณผ notify()๋ waiting pool ๋ด์ ๋๊ธฐ ์ค์ธ ์ค๋ ๋๋ฅผ ๊ตฌ๋ถํ์ง ๋ชปํ๋ฏ๋ก, ํน์ ์กฐ๊ฑด์ ๋ง์กฑํ๋ ์ค๋ ๋๋ง ๊นจ์ฐ๊ธฐ๊ฐ ์ด๋ ต์ต๋๋ค.
์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด JDK 5์์๋ java.util.concurrent.locks ํจํค์ง์์ Condition ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํฉ๋๋ค. Condition์ waiting pool ๋ด์ ์ค๋ ๋๋ฅผ ๋ถ๋ฆฌํ์ฌ ํน์ ์กฐ๊ฑด์ด ๋ง์กฑ๋ ๋๋ง ๊นจ์ฐ๋๋ก ํ ์ ์์ผ๋ฉฐ, ReentrantLock ํด๋์ค์ ํจ๊ป ์ฌ์ฉ๋ฉ๋๋ค. ๋ฐ๋ผ์ Condition์ ์ฌ์ฉํ๋ฉด wait()๊ณผ notify()์ ๋ฌธ์ ์ ์ ๋ณด์ํ ์ ์์ต๋๋ค.
public class Main {
public static final int MAX_TASK = 5;
private ReentrantLock lock = new ReentrantLock();
// lock์ผ๋ก condition ์์ฑ
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private ArrayList<String> tasks = new ArrayList<>();
// ์์
๋ฉ์๋
public void addMethod(String task) {
lock.lock(); // ์๊ณ์์ญ ์์
try {
while(tasks.size() >= MAX_TASK) {
String name = Thread.currentThread().getName();
System.out.println(name+" is waiting.");
try {
condition1.await(); // wait(); condition1 ์ฐ๋ ๋๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ฒ ํฉ๋๋ค.
Thread.sleep(500);
} catch(InterruptedException e) {}
}
tasks.add(task);
condition2.signal(); // notify(); ๊ธฐ๋ค๋ฆฌ๊ณ ์๋ condition2๋ฅผ ๊นจ์์ค๋๋ค.
System.out.println("Tasks:" + tasks.toString());
} finally {
lock.unlock(); // ์๊ณ์์ญ ๋
}
}
}