diff --git a/Thread/src/main/java/com/nhnacademy/parkminsu/assignment/Consumer.java b/Thread/src/main/java/com/nhnacademy/parkminsu/assignment/Consumer.java new file mode 100644 index 0000000..42a0954 --- /dev/null +++ b/Thread/src/main/java/com/nhnacademy/parkminsu/assignment/Consumer.java @@ -0,0 +1,58 @@ +package com.nhnacademy.parkminsu.assignment; + +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicBoolean; + +public class Consumer implements Runnable { + private Mart mart; + private Thread thread; + private AtomicBoolean isCheck; + + private int buyItem; + + public Consumer(Mart mart, String name) { + this.mart = mart; + this.thread = new Thread(this, name); + this.isCheck = new AtomicBoolean(false); + } + + public void start() { + thread.start(); + } + + public void stop() { + thread.interrupt(); + } + + public void join() throws InterruptedException { + thread.join(); + } + + public Thread getThread() { + return thread; + } + + + @Override + public void run() { + getBuyItem(); + this.mart.enterStore(buyItem); + try { + Thread.sleep(ThreadLocalRandom.current().nextInt(1000, 10000)); + this.mart.sellStoreItem(buyItem); + System.out.println(thread.getName() + "가 구매했습니다"); + isCheck.set(true); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + System.out.println(e.getMessage()); + + } + this.mart.exitStore(buyItem); + } + + private void getBuyItem() { + Random random = new Random(); + this.buyItem = random.nextInt(this.mart.getStore().length); + } +} diff --git a/Thread/src/main/java/com/nhnacademy/parkminsu/assignment/Main.java b/Thread/src/main/java/com/nhnacademy/parkminsu/assignment/Main.java new file mode 100644 index 0000000..4267dd8 --- /dev/null +++ b/Thread/src/main/java/com/nhnacademy/parkminsu/assignment/Main.java @@ -0,0 +1,29 @@ +package com.nhnacademy.parkminsu.assignment; + + +import com.nhnacademy.parkminsu.assignment.exception.NegativeNumException; + +import java.util.concurrent.ThreadLocalRandom; + + +public class Main { + public static void main(String[] args) { + try { + Mart mart = new Mart(5); + String name = "손님"; + int loop = 1; + + Producer producer = new Producer(mart); + producer.start(); + + while (true) { + Consumer consumer = new Consumer(mart, name + loop); + consumer.start(); + loop += 1; + Thread.sleep(ThreadLocalRandom.current().nextInt(1000, 10000)); + } + } catch (NegativeNumException | InterruptedException e) { + System.out.println(e.getMessage()); + } + } +} diff --git a/Thread/src/main/java/com/nhnacademy/parkminsu/assignment/Mart.java b/Thread/src/main/java/com/nhnacademy/parkminsu/assignment/Mart.java new file mode 100644 index 0000000..d85aa61 --- /dev/null +++ b/Thread/src/main/java/com/nhnacademy/parkminsu/assignment/Mart.java @@ -0,0 +1,55 @@ +package com.nhnacademy.parkminsu.assignment; + + +import com.nhnacademy.parkminsu.assignment.exception.NegativeNumException; + +public class Mart { + private Store[] store; + private int storeNum; + + public Mart(int storeNum) throws NegativeNumException { + isCheckNegativeNum(storeNum); + this.storeNum = storeNum; + initStore(); + } + + private void initStore() { + this.store = new Store[this.storeNum]; + String str = "store"; + for (int i = 0; i < store.length; i++) { + this.store[i] = new Store(str + i); + } + } + + private void isCheckNegativeNum(int num) throws NegativeNumException { + if (isNegativeNum(num)) { + throw new NegativeNumException("음수를 입력하셨습니다"); + } + } + + private boolean isNegativeNum(int num) { + return num < 0; + } + + public Store[] getStore() { + return store; + } + + public void enterStore(int buyItemStore) { + System.out.println(buyItemStore + "번 째 마트에 입장했습니다"); + store[buyItemStore].enter(); + } + + public void sellStoreItem(int buyItemStore) { + store[buyItemStore].sell(); + } + + public void exitStore(int storeNum) { + store[storeNum].exit(); + } + + public void buyStore(int storeNum) { + System.out.println("공급자가 " + storeNum + "매장에 들어갔습니다"); + store[storeNum].buy(); + } +} diff --git a/Thread/src/main/java/com/nhnacademy/parkminsu/assignment/Producer.java b/Thread/src/main/java/com/nhnacademy/parkminsu/assignment/Producer.java new file mode 100644 index 0000000..4c44be5 --- /dev/null +++ b/Thread/src/main/java/com/nhnacademy/parkminsu/assignment/Producer.java @@ -0,0 +1,49 @@ +package com.nhnacademy.parkminsu.assignment; + +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; + +/** + * N개의 품목을 납품할 수 있음 + */ +public class Producer implements Runnable { + private Mart mart; + Thread thread; + private int productItem; + + public Producer(Mart mart) { + this.mart = mart; + thread = new Thread(this); + } + + public void start() { + thread.start(); + } + + public void stop() { + thread.interrupt(); + } + + public void join() throws InterruptedException { + thread.join(); + } + + @Override + public void run() { + while (!Thread.interrupted()) { + try { + produceGood(); + Thread.sleep(ThreadLocalRandom.current().nextInt(1_000, 10_000)); + mart.buyStore(productItem); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + System.out.println(e.getMessage()); + } + } + } + + public void produceGood() { + Random random = new Random(); + this.productItem = random.nextInt(mart.getStore().length); + } +} diff --git a/Thread/src/main/java/com/nhnacademy/parkminsu/assignment/Store.java b/Thread/src/main/java/com/nhnacademy/parkminsu/assignment/Store.java new file mode 100644 index 0000000..0e3d93c --- /dev/null +++ b/Thread/src/main/java/com/nhnacademy/parkminsu/assignment/Store.java @@ -0,0 +1,94 @@ +package com.nhnacademy.parkminsu.assignment; + +import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 마트에서는 N개의 품목 매장 + * 생산자가 품목을 납품하기 전까지 어떤 품목인지는 알 수 없음 + * 소비자는 품목별로 매장을 이용할 수 있음 + */ +public class Store { + + private AtomicInteger items; + private AtomicInteger currentPeople; + private final String name; + private final int storeMaxPeople = 5; + + private final Semaphore semaphore; + + public Store(String name) { + this.name = name; + this.items = new AtomicInteger(0); + this.currentPeople = new AtomicInteger(0); + this.semaphore = new Semaphore(storeMaxPeople); + } + + /** + * 매장에 사람이 들어오면 count + 1해줌 + */ + public void enter() { + try { + this.semaphore.acquire();// +1 5명 자동 lock + System.out.println("\n" + this.name + " 매장에 손님이 들어왔습니다"); + this.currentPeople.addAndGet(1); // 손님이 들어오면 +1 + System.out.println(this.name + " 매장 손님의 수: " + currentPeople + "\n"); + + } catch (InterruptedException e) { + System.out.println(e.getMessage()); + } + + } + + public void exit() { + semaphore.release();// -1 + currentPeople.addAndGet(-1); + System.out.println(); + System.out.println(this.name + "매장에 손님이 나갔습니다"); + System.out.println(); + + } + + public synchronized void buy() { // 공급자한테 마트가 삼 + while (items.get() > 10) { + try { + System.out.println(); + System.out.println(this.name + "매장에 물품이 많습니다"); + System.out.println(); + wait(); + } catch (InterruptedException e) { + System.out.println(e.getMessage()); + Thread.currentThread().interrupt(); + } + } + if (items.get() <= 0) { + notifyAll(); + } + items.addAndGet(1); + System.out.println(); + System.out.println(this.name + "매장에 물품을 추가했습니다"); + System.out.println(this.name + "매장 현재 물품 수: " + items.get()); + System.out.println(); + + + } + + public synchronized void sell() { // 소비자 파는거 + while (items.get() <= 0) {// 물품이 없을 때 + try { + System.out.println(); + System.out.println(this.name + "매장에 물품이 없습니다"); + System.out.println(); + wait(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + notifyAll(); + items.addAndGet(-1); // -1 + System.out.println(this.name + "매장에 현재 남은 물품: " + items.get()); + System.out.println(); + } + + +} diff --git a/Thread/src/main/java/com/nhnacademy/parkminsu/assignment/exception/NegativeNumException.java b/Thread/src/main/java/com/nhnacademy/parkminsu/assignment/exception/NegativeNumException.java new file mode 100644 index 0000000..4229c53 --- /dev/null +++ b/Thread/src/main/java/com/nhnacademy/parkminsu/assignment/exception/NegativeNumException.java @@ -0,0 +1,7 @@ +package com.nhnacademy.parkminsu.assignment.exception; + +public class NegativeNumException extends Exception { + public NegativeNumException(String message) { + super(message); + } +} diff --git a/Thread/src/main/java/com/nhnacademy/parkminsu/exam/Consumer.java b/Thread/src/main/java/com/nhnacademy/parkminsu/exam/Consumer.java new file mode 100644 index 0000000..91e0981 --- /dev/null +++ b/Thread/src/main/java/com/nhnacademy/parkminsu/exam/Consumer.java @@ -0,0 +1,48 @@ +package com.nhnacademy.parkminsu.exam; + +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * 소비자는 매장에 입장 후 물건을 구매 + * 매장에는 입장 인원 제한이 있으므로 인원 초과시 기다림 + * 매장에 입장하면 물거은 구매하고 퇴장 + * 1~10초 간격으로 구매 + */ +public class Consumer implements Runnable { + private Store store; + private Thread thread; + private AtomicBoolean isCheck; + + + public Consumer(String name, Store store) { + this.thread = new Thread(this, name); + this.store = store; + this.isCheck = new AtomicBoolean(false); + } + + public void start() { + thread.start(); + } + + public void stop() { + thread.interrupt(); + } + + + @Override + public void run() { + store.enter(); + try { + Thread.sleep(ThreadLocalRandom.current().nextInt(1000, 10000)); + store.sell(); + System.out.println(thread.getName() + "가 구매했습니다"); + isCheck.set(true); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + System.out.println(e.getMessage()); + } + + store.exit(); + } +} diff --git a/Thread/src/main/java/com/nhnacademy/parkminsu/exam/Main.java b/Thread/src/main/java/com/nhnacademy/parkminsu/exam/Main.java new file mode 100644 index 0000000..2b9e083 --- /dev/null +++ b/Thread/src/main/java/com/nhnacademy/parkminsu/exam/Main.java @@ -0,0 +1,23 @@ +package com.nhnacademy.parkminsu.exam; + +public class Main { + public static void main(String[] args) throws InterruptedException { + Store store = new Store(); + String name = "손님"; + int loop = 1; + Proceducer proceducer = new Proceducer(store); + proceducer.start(); + + while (true) { + Consumer consumer = new Consumer(name + loop, store); + + + consumer.start(); + loop += 1; + Thread.sleep(1500); + //Thread.sleep(ThreadLocalRandom.current().nextInt(1000, 10000)); + + + } + } +} diff --git a/Thread/src/main/java/com/nhnacademy/parkminsu/exam/Proceducer.java b/Thread/src/main/java/com/nhnacademy/parkminsu/exam/Proceducer.java new file mode 100644 index 0000000..eb99263 --- /dev/null +++ b/Thread/src/main/java/com/nhnacademy/parkminsu/exam/Proceducer.java @@ -0,0 +1,42 @@ +package com.nhnacademy.parkminsu.exam; + +import java.util.concurrent.ThreadLocalRandom; + +/** + * 생산자는 매장에 물건이 부족하지 않도록 채워둠 + * 물건은 1~10초 간격으로 채움 + * Thread내에서 난수 생성을 위해서는 ThreadLocalRandom.current().nextInt() + * 사용 + */ +public class Proceducer implements Runnable { + private final Store store; + private Thread thread; + + public Proceducer(Store store) { + this.store = store; + thread = new Thread(this); + } + + public void start() { + thread.start(); + } + + public void stop() { + thread.interrupt(); + } + + @Override + public void run() { + try { + while (!Thread.interrupted()) { + Thread.sleep(ThreadLocalRandom.current().nextInt(1000, 10000)); + store.buy(); + } + } catch (InterruptedException e) { + System.out.println(e.getMessage()); + Thread.currentThread().interrupt(); + + } + + } +} diff --git a/Thread/src/main/java/com/nhnacademy/parkminsu/exam/Store.java b/Thread/src/main/java/com/nhnacademy/parkminsu/exam/Store.java new file mode 100644 index 0000000..850ea5d --- /dev/null +++ b/Thread/src/main/java/com/nhnacademy/parkminsu/exam/Store.java @@ -0,0 +1,90 @@ +package com.nhnacademy.parkminsu.exam; + +import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 물건을 납품 받아서 판매 + * 10개의 물건만 전시 + * 매장은 최대 5명까지만 동시 입장 + * 물건 구매는 동시에 1명만 가능 + * 물건 판매 후 빈 공간에 생기면 생산자에게 알려줌 + * 물건 납품은 동시에 1명만 가능 + * 매장에서 물건이 들어오면 소비자에게 알려줌 + */ +public class Store { + private final AtomicInteger consumerCount; + private final AtomicInteger thingsCount; + private final Semaphore semaphore; + + @SuppressWarnings("checkstyle:MissingJavadocMethod") + public Store() { + semaphore = new Semaphore(5); + consumerCount = new AtomicInteger(0); + thingsCount = new AtomicInteger(0); + } + + /** + * 손님이 들어오면 count가 1 증가 + */ + public void enter() { + try { + semaphore.acquire(); + consumerCount.addAndGet(1); // +1 + System.out.println(); + System.out.println("입장했습니다"); + System.out.println("사람 수: " + consumerCount.get()); + } catch (InterruptedException e) { + System.out.println(e.getMessage()); + } + } + + /** + * 손님이 나가면 count를 1 감소 + */ + public void exit() { + consumerCount.addAndGet(-1); + System.out.println("손님이 나갔습니다"); + System.out.println(); + semaphore.release(); + } + + + public synchronized void buy() { // 공급자한테 마트가 삼 + while (thingsCount.get() > 10) { + try { + System.out.println("물품이 많습니다"); + wait(); + } catch (InterruptedException e) { + System.out.println(e.getMessage()); + Thread.currentThread().interrupt(); + } + } + thingsCount.addAndGet(1); + System.out.println(); + System.out.println("물품을 추가했습니다"); + System.out.println("현재 물품 수: " + thingsCount.get()); + System.out.println(); + + notifyAll(); + } + + public synchronized void sell() { // 소비자 파는거 + while (thingsCount.get() <= 0) {// 물품이 없을 때 + try { + System.out.println("물품이 없습니다"); + System.out.println(); + wait(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + notifyAll(); + thingsCount.addAndGet(-1); // -1 + System.out.println("상품을 판매했습니다"); + System.out.println("현재 남은 물품: " + thingsCount.get()); + System.out.println(); + + + } +}