diff --git a/Thread/src/main/java/com/nhnacademy/Jminsoo/exercise/Consumer.java b/Thread/src/main/java/com/nhnacademy/Jminsoo/exercise/Consumer.java
new file mode 100644
index 0000000..611d840
--- /dev/null
+++ b/Thread/src/main/java/com/nhnacademy/Jminsoo/exercise/Consumer.java
@@ -0,0 +1,48 @@
+package com.nhnacademy.Jminsoo.exercise;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * 소비자는 매장에 입장 후 물건을 구매할 수 있다.
+ *
+ * 매장에는 입장 인원 제한이 있으므로, 인원 초과시 기다린다.
+ *
+ * 매장에 입장하면 물건을 구매하고, 퇴장한다.
+ *
+ * 1~10초 간격으로 구매한다.
+ */
+public class Consumer implements Runnable {
+
+ private Store store;
+ private String name;
+ private Thread thread;
+
+
+ public Consumer(String name, Store store) {
+ this.name = name;
+ this.store = store;
+ this.thread = new Thread(this, name);
+ }
+
+ public void start() {
+ this.thread.start();
+ }
+
+ @Override
+ public void run() {
+ try {
+ this.store.enter();
+ System.out.println(this.name + " 입장! 현재 손님 수 : " + this.store.getConsumerCount());
+ int randNum = ThreadLocalRandom.current().nextInt(1, 11);
+ Thread.sleep(randNum * 1_000L);
+ this.store.sell();
+ System.out.println(this.name + " 구매! 현재 물건 개수 : " + this.store.getGoodsCount());
+ this.store.exit();
+ System.out.println(
+ this.name + " 퇴장! 현재 손님 수 : " + this.store.getConsumerCount());
+
+ } catch (InterruptedException ignore) {
+
+ }
+ }
+}
diff --git a/Thread/src/main/java/com/nhnacademy/Jminsoo/exercise/Main.java b/Thread/src/main/java/com/nhnacademy/Jminsoo/exercise/Main.java
new file mode 100644
index 0000000..438fb2f
--- /dev/null
+++ b/Thread/src/main/java/com/nhnacademy/Jminsoo/exercise/Main.java
@@ -0,0 +1,25 @@
+package com.nhnacademy.Jminsoo.exercise;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadLocalRandom;
+
+public class Main {
+ public static void main(String[] args) throws InterruptedException {
+ Store store = new Store();
+ Producer producer = new Producer(store);
+ ExecutorService executorService = Executors.newFixedThreadPool(5);
+ producer.start();
+ int index = 0;
+ while (true) {
+// if (store.getConsumerCount() < store.getMAX_CONSUMER_COUNTS()) {
+ index++;
+ executorService.submit(new Consumer("손님" + index, store));
+ int randNum = ThreadLocalRandom.current().nextInt(1, 11);
+ Thread.sleep(randNum * 1_000L);
+// }
+ }
+
+ }
+}
+
diff --git a/Thread/src/main/java/com/nhnacademy/Jminsoo/exercise/Producer.java b/Thread/src/main/java/com/nhnacademy/Jminsoo/exercise/Producer.java
new file mode 100644
index 0000000..a7dfd36
--- /dev/null
+++ b/Thread/src/main/java/com/nhnacademy/Jminsoo/exercise/Producer.java
@@ -0,0 +1,41 @@
+package com.nhnacademy.Jminsoo.exercise;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * 생산자는 매장에 물건이 부족하지 않도록 채워둔다.
+ *
+ * 물건은 1~10초 간격으로 채운다.
+ *
+ * Thread내에서 난수 생성을 위해서는 ThreadLocalRandom.current().nextInt()를 사용하면 된다
+ */
+public class Producer implements Runnable {
+ private Thread thread;
+ private Store store;
+
+ public Producer(Store store) {
+ this.thread = new Thread(this);
+ this.store = store;
+ }
+
+ public void start() {
+ this.thread.start();
+ }
+
+ @Override
+ public void run() {
+ try {
+ while (true) {
+ System.out.println("물건 공급 중!");
+ Thread.sleep(getRandNum() * 1_000L);
+ this.store.buy();
+ System.out.println("물건 공급 완료! 현재 물건 개수 : " + this.store.getGoodsCount());
+ }
+ } catch (InterruptedException ignore) {
+ }
+ }
+
+ private int getRandNum() {
+ return ThreadLocalRandom.current().nextInt(1, 11);
+ }
+}
diff --git a/Thread/src/main/java/com/nhnacademy/Jminsoo/exercise/Store.java b/Thread/src/main/java/com/nhnacademy/Jminsoo/exercise/Store.java
new file mode 100644
index 0000000..cec0ccd
--- /dev/null
+++ b/Thread/src/main/java/com/nhnacademy/Jminsoo/exercise/Store.java
@@ -0,0 +1,80 @@
+package com.nhnacademy.Jminsoo.exercise;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * 매장은 물건을 납품 받아서 판매한다.
+ *
+ * 매장에는 최대 10개의 물건만 전시할 수 있다. : 최대 물건 개수
+ *
+ * 매장은 최대 5명까지만 동시 입장 가능하다. : Consumer의 최대 접근 개수
+ *
+ * 매장에서 물건 구매는 동시에 1명만 가능하다. : Syncronized.
+ *
+ * 매장에서 물건 판매 후 빈 공간에 생기면 생산자에게 알려 준다. : 생산자는 물건이 비면 깨어난다
+ *
+ * 매장에서 물건 납품은 동시에 1명만 가능하다. : 납품 Syncronized
+ *
+ * 매장에서 물건이 들어오면 소비자에게 알려 준다. : 빈 물건이 들어오면 깬다.
+ */
+public class Store {
+ private final AtomicInteger MAX_GOODS_COUNTS = new AtomicInteger(10);
+ private final AtomicInteger MAX_CONSUMER_COUNTS = new AtomicInteger(5);
+ private AtomicInteger goodsCount;
+
+ private AtomicInteger consumerCount;
+
+
+ public Store() {
+ this.goodsCount = new AtomicInteger(0);
+ this.consumerCount = new AtomicInteger(0);
+
+ }
+
+ public void enter() throws InterruptedException {
+
+ if (this.consumerCount.get() >= this.MAX_CONSUMER_COUNTS.get()) {
+ wait();
+ }
+ this.consumerCount.addAndGet(1);
+ }
+
+ public void exit() {
+ this.consumerCount.addAndGet(-1);
+ }
+
+ public synchronized void buy() throws InterruptedException {
+ while (this.goodsCount.get() >= this.MAX_GOODS_COUNTS.get()) {
+ System.out.println("창고가 꽉 찼다! 대기!");
+ wait();
+
+ }
+ this.goodsCount.addAndGet(1);
+ notifyAll();
+ }
+
+ public synchronized void sell() throws InterruptedException {
+ while (this.goodsCount.get() <= 0) {
+ wait();
+ }
+ this.goodsCount.addAndGet(-1);
+ notifyAll();
+ }
+
+ public synchronized int getGoodsCount() {
+ return this.goodsCount.intValue();
+ }
+
+ public synchronized int getConsumerCount() {
+ return this.consumerCount.intValue();
+ }
+
+ public synchronized int getMAX_GOODS_COUNTS() {
+ return this.MAX_GOODS_COUNTS.intValue();
+ }
+
+ public synchronized int getMAX_CONSUMER_COUNTS() {
+ return this.MAX_CONSUMER_COUNTS.intValue();
+ }
+}
+
diff --git a/Thread/src/main/java/com/nhnacademy/Jminsoo/one/Consumer.java b/Thread/src/main/java/com/nhnacademy/Jminsoo/one/Consumer.java
new file mode 100644
index 0000000..972f676
--- /dev/null
+++ b/Thread/src/main/java/com/nhnacademy/Jminsoo/one/Consumer.java
@@ -0,0 +1,31 @@
+package com.nhnacademy.Jminsoo.one;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+public class Consumer implements Runnable {
+
+ private Mart mart;
+ private String name;
+ private Thread thread;
+
+ public Consumer(String name, Mart mart) {
+ this.name = name;
+ this.mart = mart;
+ this.thread = new Thread(this, name);
+ }
+
+ public void start() {
+ this.thread.start();
+ }
+
+ @Override
+ public void run() {
+ try {
+ this.mart.enter();
+ int randNum = ThreadLocalRandom.current().nextInt(1, 11);
+ Thread.sleep(randNum * 1000);
+ } catch (InterruptedException ignore) {
+ }
+ System.out.println(this.name + " 마트 탈출!");
+ }
+}
diff --git a/Thread/src/main/java/com/nhnacademy/Jminsoo/one/Main.java b/Thread/src/main/java/com/nhnacademy/Jminsoo/one/Main.java
new file mode 100644
index 0000000..f3dd7ae
--- /dev/null
+++ b/Thread/src/main/java/com/nhnacademy/Jminsoo/one/Main.java
@@ -0,0 +1,21 @@
+package com.nhnacademy.Jminsoo.one;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+
+public class Main {
+ public static void main(String[] args) throws InterruptedException {
+ Mart mart = new Mart();
+ Producer producer = new Producer(mart);
+ producer.start();
+
+
+ int index = 0;
+ while (true) {
+ index++;
+ new Consumer("손님" + index, mart).start();
+ int randNum = ThreadLocalRandom.current().nextInt(1, 4);
+ Thread.sleep(randNum * 1_000L);
+ }
+ }
+}
diff --git a/Thread/src/main/java/com/nhnacademy/Jminsoo/one/Mart.java b/Thread/src/main/java/com/nhnacademy/Jminsoo/one/Mart.java
new file mode 100644
index 0000000..ee50239
--- /dev/null
+++ b/Thread/src/main/java/com/nhnacademy/Jminsoo/one/Mart.java
@@ -0,0 +1,61 @@
+package com.nhnacademy.Jminsoo.one;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class Mart {
+
+ private List storeList;
+ private final AtomicInteger martSize;
+ private AtomicInteger randNum;
+
+
+ public Mart() {
+ this.martSize = new AtomicInteger(StoreType.values().length);
+ this.storeList = new ArrayList<>();
+ this.randNum = new AtomicInteger(0);
+ addStore();
+ }
+
+ private void addStore() {
+ for (StoreType type : StoreType.values()) {
+ this.storeList.add(new Store(type.name()));
+ }
+ }
+
+ public void supply() throws InterruptedException {
+ setRandNum();
+ this.storeList.get(this.randNum.get()).buy();
+ }
+
+
+ public void enter() throws InterruptedException {
+ setRandNum();
+ Store tempStore = this.storeList.get(randNum.get());
+ if (tempStore.getConsumerCount() < tempStore.getMaxConsumerCount()) {
+ tempStore.enter();
+ tempStore.sell();
+ tempStore.exit();
+ }
+ }
+
+ public synchronized void setRandNum() {
+ this.randNum.set(ThreadLocalRandom.current().nextInt(1, this.martSize.get()));
+ }
+
+ private enum StoreType {
+ 축산매장,
+ 수산매장,
+ 빵집,
+ 피자집,
+ 삼성스토어,
+ 애플스토어,
+ 당X치킨,
+ 일반과자집;
+
+
+ }
+
+}
diff --git a/Thread/src/main/java/com/nhnacademy/Jminsoo/one/Producer.java b/Thread/src/main/java/com/nhnacademy/Jminsoo/one/Producer.java
new file mode 100644
index 0000000..2f623c6
--- /dev/null
+++ b/Thread/src/main/java/com/nhnacademy/Jminsoo/one/Producer.java
@@ -0,0 +1,34 @@
+package com.nhnacademy.Jminsoo.one;
+
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class Producer implements Runnable {
+ private Thread thread;
+ private Mart mart;
+
+ private AtomicInteger randNum;
+
+
+ public Producer(Mart mart) {
+ this.thread = new Thread(this);
+ this.mart = mart;
+ this.randNum = new AtomicInteger();
+ }
+
+ public void start() {
+ this.thread.start();
+ }
+
+ @Override
+ public void run() {
+ try {
+ while (true) {
+ this.randNum.set(ThreadLocalRandom.current().nextInt(1, 6));
+ Thread.sleep(randNum.get() * 100);
+ this.mart.supply();
+ }
+ } catch (InterruptedException ignore) {
+ }
+ }
+}
diff --git a/Thread/src/main/java/com/nhnacademy/Jminsoo/one/Store.java b/Thread/src/main/java/com/nhnacademy/Jminsoo/one/Store.java
new file mode 100644
index 0000000..87abb78
--- /dev/null
+++ b/Thread/src/main/java/com/nhnacademy/Jminsoo/one/Store.java
@@ -0,0 +1,80 @@
+package com.nhnacademy.Jminsoo.one;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class Store {
+ private final AtomicInteger MAX_GOODS_COUNTS = new AtomicInteger(10);
+ private final AtomicInteger MAX_CONSUMER_COUNTS = new AtomicInteger(5);
+ private AtomicInteger goodsCount;
+
+ private AtomicInteger consumerCount;
+
+ private String name;
+
+
+ public Store(String name) {
+ this.goodsCount = new AtomicInteger(0);
+ this.consumerCount = new AtomicInteger(0);
+ this.name = name;
+ }
+
+ public void enter() {
+ while (this.getConsumerCount() >= this.getMaxConsumerCount()) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ this.consumerCount.addAndGet(1);
+ System.out.println("[구매자] " + this.name + " 입장! 현재 손님 수 : " + this.getConsumerCount());
+
+ }
+
+ public void exit() {
+ System.out.println(
+ "[구매자] " + this.name + " 퇴장! 현재 손님 수 : " + this.getConsumerCount());
+ this.consumerCount.addAndGet(-1);
+ }
+
+ public synchronized void buy() {
+ System.out.println("[공급자] " + this.name + " 물건 공급 중!");
+ if (this.getGoodsCount() >= this.getMaxGoodsCount()) {
+ System.out.println("[공급자] " + this.name + " 창고가 꽉 찼다! 대기!");
+ } else {
+ this.goodsCount.addAndGet(1);
+ System.out.println("[공급자] " + this.name + " 물건 공급 완료! 현재 물건 개수 : " + this.getGoodsCount());
+ notifyAll();
+ }
+ }
+
+ public synchronized void sell() throws InterruptedException {
+
+ while (this.goodsCount.get() <= 0) {
+ System.out.println("[구매자] " + this.name + " 구매자 물건 없어서 대기!");
+ wait();
+ }
+ this.goodsCount.addAndGet(-1);
+ System.out.println("[구매자] " + this.name + " 물건 판매! 현재 물건 개수 : " + this.getGoodsCount());
+ notifyAll();
+ }
+
+ public synchronized int getGoodsCount() {
+ return this.goodsCount.intValue();
+ }
+
+ public synchronized int getConsumerCount() {
+ return this.consumerCount.intValue();
+ }
+
+ public synchronized int getMaxGoodsCount() {
+ return this.MAX_GOODS_COUNTS.intValue();
+ }
+
+ public synchronized int getMaxConsumerCount() {
+ return this.MAX_CONSUMER_COUNTS.intValue();
+ }
+
+
+}
+
diff --git a/Thread/src/main/java/com/nhnacademy/Jminsoo/seamaphore/Consumer.java b/Thread/src/main/java/com/nhnacademy/Jminsoo/seamaphore/Consumer.java
new file mode 100644
index 0000000..837bc15
--- /dev/null
+++ b/Thread/src/main/java/com/nhnacademy/Jminsoo/seamaphore/Consumer.java
@@ -0,0 +1,32 @@
+package com.nhnacademy.Jminsoo.seamaphore;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+public class Consumer implements Runnable {
+
+ private Mart mart;
+ private String name;
+ private Thread thread;
+
+
+ public Consumer(String name, Mart mart) {
+ this.name = name;
+ this.mart = mart;
+ this.thread = new Thread(this, name);
+ }
+
+ public void start() {
+ this.thread.start();
+ }
+
+ @Override
+ public void run() {
+ try {
+ this.mart.enter();
+ int randNum = ThreadLocalRandom.current().nextInt(1, 11);
+ Thread.sleep(randNum * 1_000L);
+ } catch (InterruptedException ignore) {
+ }
+ System.out.println(this.name + " 마트 탈출!");
+ }
+}
diff --git a/Thread/src/main/java/com/nhnacademy/Jminsoo/seamaphore/Main.java b/Thread/src/main/java/com/nhnacademy/Jminsoo/seamaphore/Main.java
new file mode 100644
index 0000000..b57c6e8
--- /dev/null
+++ b/Thread/src/main/java/com/nhnacademy/Jminsoo/seamaphore/Main.java
@@ -0,0 +1,21 @@
+package com.nhnacademy.Jminsoo.seamaphore;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+
+public class Main {
+ public static void main(String[] args) throws InterruptedException {
+ Mart mart = new Mart();
+ Producer producer = new Producer(mart);
+ producer.start();
+
+
+ int index = 0;
+ while (true) {
+ index++;
+ new Consumer("손님" + index, mart).start();
+ int randNum = ThreadLocalRandom.current().nextInt(1, 6);
+ Thread.sleep(randNum * 1_000L);
+ }
+ }
+}
diff --git a/Thread/src/main/java/com/nhnacademy/Jminsoo/seamaphore/Mart.java b/Thread/src/main/java/com/nhnacademy/Jminsoo/seamaphore/Mart.java
new file mode 100644
index 0000000..5a8b27c
--- /dev/null
+++ b/Thread/src/main/java/com/nhnacademy/Jminsoo/seamaphore/Mart.java
@@ -0,0 +1,56 @@
+package com.nhnacademy.Jminsoo.seamaphore;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class Mart {
+
+ private List storeList;
+ private final AtomicInteger martSize;
+
+
+ public Mart() {
+ this.martSize = new AtomicInteger(StoreType.values().length);
+ this.storeList = new ArrayList<>();
+ addStore();
+ }
+
+ private void addStore() {
+ for (StoreType type : StoreType.values()) {
+ this.storeList.add(new Store(type.name()));
+ }
+ }
+
+ public void supply() {
+ this.storeList.get(this.getRandNum(this.martSize.get())).buy();
+ }
+
+
+ public void enter() throws InterruptedException {
+ Store tempStore = this.storeList.get(this.getRandNum(this.martSize.get()));
+ tempStore.enter();
+ tempStore.sell();
+ tempStore.exit();
+ }
+
+ private int getRandNum(int bound) {
+ return ThreadLocalRandom.current().nextInt(1, bound);
+ }
+
+ private enum StoreType {
+ 축산매장,
+ 수산매장,
+ 빵집,
+ 피자집,
+ 삼성스토어,
+ 애플스토어,
+ 당X치킨,
+ 일반과자집;
+
+
+ }
+
+
+}
diff --git a/Thread/src/main/java/com/nhnacademy/Jminsoo/seamaphore/Producer.java b/Thread/src/main/java/com/nhnacademy/Jminsoo/seamaphore/Producer.java
new file mode 100644
index 0000000..fc41a89
--- /dev/null
+++ b/Thread/src/main/java/com/nhnacademy/Jminsoo/seamaphore/Producer.java
@@ -0,0 +1,34 @@
+package com.nhnacademy.Jminsoo.seamaphore;
+
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class Producer implements Runnable {
+ private Thread thread;
+ private Mart mart;
+
+ private AtomicInteger randNum;
+
+
+ public Producer(Mart mart) {
+ this.thread = new Thread(this);
+ this.mart = mart;
+ this.randNum = new AtomicInteger();
+ }
+
+ public void start() {
+ this.thread.start();
+ }
+
+ @Override
+ public void run() {
+ try {
+ while (true) {
+ this.randNum.set(ThreadLocalRandom.current().nextInt(1, 6));
+ Thread.sleep(randNum.get() * 1_000L);
+ this.mart.supply();
+ }
+ } catch (InterruptedException ignore) {
+ }
+ }
+}
diff --git a/Thread/src/main/java/com/nhnacademy/Jminsoo/seamaphore/Store.java b/Thread/src/main/java/com/nhnacademy/Jminsoo/seamaphore/Store.java
new file mode 100644
index 0000000..cc21f0f
--- /dev/null
+++ b/Thread/src/main/java/com/nhnacademy/Jminsoo/seamaphore/Store.java
@@ -0,0 +1,60 @@
+package com.nhnacademy.Jminsoo.seamaphore;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class Store {
+ private final AtomicInteger MAX_GOODS_COUNTS = new AtomicInteger(10);
+ private AtomicInteger goodsCount;
+
+ private AtomicInteger consumerCount;
+
+ private String name;
+
+ private final Semaphore consumerSemaphore;
+
+
+ public Store(String name) {
+ this.goodsCount = new AtomicInteger(0);
+ this.consumerCount = new AtomicInteger(0);
+ this.name = name;
+ this.consumerSemaphore = new Semaphore(5, true);
+ }
+
+ public void enter() throws InterruptedException {
+ System.out.println(
+ "[구매자] " + this.name + " 입장! 현재 손님 수 : " + this.consumerCount.get());
+ this.consumerSemaphore.acquire();
+ this.consumerCount.addAndGet(1);
+
+ }
+
+ public void exit() {
+ System.out.println(
+ "[구매자] " + this.name + " 퇴장! 현재 손님 수 : " + this.consumerCount.get());
+ this.consumerCount.addAndGet(-1);
+ this.consumerSemaphore.release();
+ }
+
+
+ public synchronized void buy() {
+ System.out.println("[공급자] " + this.name + " 물건 공급 중!");
+ if (this.goodsCount.get() >= this.MAX_GOODS_COUNTS.get()) {
+ System.out.println("[공급자] " + this.name + " 창고가 꽉 찼다! 대기!");
+ } else {
+ this.goodsCount.addAndGet(1);
+ System.out.println("[공급자] " + this.name + " 물건 공급 완료! 현재 물건 개수 : " + this.goodsCount.get());
+ notifyAll();
+ }
+ }
+
+ public synchronized void sell() throws InterruptedException {
+ while (this.goodsCount.get() <= 0) {
+ wait();
+ }
+ this.goodsCount.addAndGet(-1);
+ System.out.println("[구매자] " + this.name + " 물건 판매! 현재 물건 개수 : " + this.goodsCount.get());
+ notifyAll();
+ }
+}
+