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(); + } +} +