diff --git a/ErzeugerVerbraucher/.idea/vcs.xml b/ErzeugerVerbraucher/.idea/vcs.xml new file mode 100644 index 0000000000000000000000000000000000000000..6c0b8635858dc7ad44b93df54b762707ce49eefc --- /dev/null +++ b/ErzeugerVerbraucher/.idea/vcs.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="VcsDirectoryMappings"> + <mapping directory="$PROJECT_DIR$/.." vcs="Git" /> + </component> +</project> \ No newline at end of file diff --git a/ErzeugerVerbraucher/out/production/Aufgabe4/Main.class b/ErzeugerVerbraucher/out/production/Aufgabe4/Main.class deleted file mode 100644 index e92adf7d8f256d86b5d8e1080fd1e655c523f9d9..0000000000000000000000000000000000000000 Binary files a/ErzeugerVerbraucher/out/production/Aufgabe4/Main.class and /dev/null differ diff --git a/ErzeugerVerbraucher/src/Buffer.java b/ErzeugerVerbraucher/src/Buffer.java index e91ea1b08656681d1f1fe36aea5520a6118984b6..a1101dcfc5302ca275ec6272afb2635cb6babcf3 100644 --- a/ErzeugerVerbraucher/src/Buffer.java +++ b/ErzeugerVerbraucher/src/Buffer.java @@ -1,53 +1,65 @@ -import java.util.ArrayList; -import java.util.concurrent.Semaphore; -import java.lang.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReferenceArray; +/** + * A generic and atomically safe Buffer data structure for holding values important in multithreaded use cases. + * @param <T> The type of item to hold within the Buffer + */ public class Buffer<T> { + AtomicReferenceArray<T> items; + AtomicInteger itemCount; int size; - public Semaphore sem; - public ArrayList<T> items = new ArrayList<T>(size); - public Buffer(int size){ - assert size >= 0; + /** + * Constructor for Buffer data structure + * @param size The size of the Buffer + */ + public Buffer(int size) { + this.items = new AtomicReferenceArray<>(size); + this.itemCount = new AtomicInteger(0); this.size = size; - } - public void push(T e) throws InterruptedException { - assert(e!=null); - assert(!full()); - if(this.full()) { - System.out.println("Buffer is full"); + /** + * Push an item to the Buffer + * @param item The item to be pushed + * @throws IllegalStateException Thrown if pushing would exceed the maximum allowed size + */ + public void push(T item) throws IllegalStateException { + if (this.itemCount.get() >= this.size) { + throw new IllegalStateException(); } - this.sem.acquire(); - items.add(e); - this.sem.release(); + this.items.set(this.itemCount.get(), item); + this.itemCount.incrementAndGet(); } -// public ArrayList<T> pop() throws InterruptedException{ -// sem.acquire(); -// item = items.remove(0); -// sem.release(); -// return item; -// -// } - - public boolean full() throws InterruptedException { - sem.acquire(); - boolean is_full = items.size()==size; - sem.release(); - - return is_full; + /** + * Pop an item from the Buffer + * @return The item to be popped + * @throws IllegalStateException Thrown if popping would underflow the minimum allowed size + */ + public T pop() throws IllegalStateException { + if (this.itemCount.get() <= 0) { /// ORIGINAL <1 + throw new IllegalStateException(); + } + return this.items.getAndSet(this.itemCount.getAndDecrement(), null); } - public boolean empty() throws InterruptedException { - sem.acquire(); - boolean is_empty = items.size()==0; - sem.release(); - - return is_empty; + /** + * Check whether the Buffer is full + * @return True if the Buffer is full, False otherwise + */ + public boolean full() { + return this.itemCount.get() >= this.size; + } + /** + * Check whether the Buffer is empty + * @return True if the Buffer is empty, False otherwise + */ + public boolean empty() { + return Integer.valueOf(this.itemCount.get()).equals(0); } } diff --git a/ErzeugerVerbraucher/src/Car.java b/ErzeugerVerbraucher/src/Car.java index fa9b88972a765f29f5fc3073908e682c4b2b33ca..5cad0e429aed19d1f84f37de0292c6268e3dd089 100644 --- a/ErzeugerVerbraucher/src/Car.java +++ b/ErzeugerVerbraucher/src/Car.java @@ -1,3 +1,2 @@ public class Car { - } diff --git a/ErzeugerVerbraucher/src/Consumer.java b/ErzeugerVerbraucher/src/Consumer.java index 2b16e6a3695443a1d5e39edc11f4c630705f0fb9..e576eb84c11d90af2ea54dcf216111583a37cfc4 100644 --- a/ErzeugerVerbraucher/src/Consumer.java +++ b/ErzeugerVerbraucher/src/Consumer.java @@ -1,34 +1,49 @@ -import com.sun.jdi.event.ThreadDeathEvent; -import com.sun.jdi.event.ThreadStartEvent; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; -import java.util.Random; -import java.lang.*; +public class Consumer implements Runnable { + private final Buffer<Car> buffer; + private final int interval; + private final AtomicBoolean asleep; + private final AtomicBoolean wakeCall; -public class Consumer{ - int interval; - ThreadDeathEvent consumerThread; - ThreadStartEvent producerThread; - Buffer buffer; - public Consumer(Buffer buffer, int interval, ThreadDeathEvent consumerThread, ThreadStartEvent producerThread) { - assert buffer != null; - assert interval > 0; + public Consumer(Buffer<Car> buffer, int interval, AtomicBoolean asleep, AtomicBoolean wakeCall) { this.buffer = buffer; this.interval = interval; - this.consumerThread = consumerThread; - this.producerThread = producerThread; - this.run(); - - assert this.interval == interval; + this.asleep = asleep; + this.wakeCall = wakeCall; } - public void run() throws InterruptedException{ - assert this.interval > 0; - while(this.interval > 0) { - Thread.sleep(new Random().nextInt(interval)); + @Override + public void run() { + while(true) { + try { + TimeUnit.SECONDS.sleep((int)(Math.random() * this.interval + 1)); + + boolean wasFull = this.buffer.full(); + + if (!this.asleep.get()) { + System.out.printf("%s consumer ...%n", Thread.currentThread().getId()); + + if (!this.buffer.empty()) { + this.buffer.pop(); + System.out.printf( + "%s consumer TAKING OUT %s/%s %n", + Thread.currentThread().getId(), + this.buffer.itemCount, + this.buffer.size + ); + } else { + this.asleep.set(true); + } + } - boolean was_full = this.buffer.full(); - assert was_full instanceof - if(!this.consumerThread.) + if (wasFull) { + this.wakeCall.set(false); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } } } } diff --git a/ErzeugerVerbraucher/src/Main.java b/ErzeugerVerbraucher/src/Main.java index df9fa5fe8668f1980bd6e02e19aeea7bf25d6c89..c84216147c5d931cb9183741807851e646f8c6fc 100644 --- a/ErzeugerVerbraucher/src/Main.java +++ b/ErzeugerVerbraucher/src/Main.java @@ -1,12 +1,35 @@ +import java.util.concurrent.atomic.AtomicBoolean; + public class Main { public static void main(String[] args) { - Buffer b1 = new Buffer(5); - try { - b1.push(5); - } catch (InterruptedException e) { - System.out.println(e); + Buffer<Car> buffer = new Buffer<>(5); + AtomicBoolean consumerStatus = new AtomicBoolean(false); + AtomicBoolean producerStatus = new AtomicBoolean(false); + int consumerCount = Integer.parseInt(args[0]); + int producerCount = Integer.parseInt(args[1]); + + for (int i = 0; i < consumerCount; i++) { + Thread consumerThread = new Thread(new Runnable() { + @Override + public void run() { + Consumer consumer = new Consumer(buffer, 15, consumerStatus, producerStatus); + consumer.run(); + } + }); + + consumerThread.start(); } + for (int i = 0; i < producerCount; i++) { + Thread producerThread = new Thread(new Runnable() { + @Override + public void run() { + Producer producer = new Producer(buffer, 15, producerStatus, consumerStatus); + producer.run(); + } + }); + producerThread.start(); + } } -} +} \ No newline at end of file diff --git a/ErzeugerVerbraucher/src/Producer.java b/ErzeugerVerbraucher/src/Producer.java index e715fa6177d3b553a51a46a36fdfa65e5113fbba..2f89cf44cf75b28ab6285d544bc0160eb161b0a9 100644 --- a/ErzeugerVerbraucher/src/Producer.java +++ b/ErzeugerVerbraucher/src/Producer.java @@ -1,2 +1,49 @@ -public class Producer { +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +public class Producer implements Runnable { + private final Buffer<Car> buffer; + private final int interval; + private final AtomicBoolean asleep; + private final AtomicBoolean wakeCall; + + public Producer(Buffer<Car> buffer, int interval, AtomicBoolean asleep, AtomicBoolean wakeCall) { + this.buffer = buffer; + this.interval = interval; + this.asleep = asleep; + this.wakeCall = wakeCall; + } + + @Override + public void run() { + while(true) { + try { + TimeUnit.SECONDS.sleep((int)(Math.random() * this.interval + 1)); + + boolean wasEmpty = this.buffer.empty(); + + if (!this.asleep.get()) { + System.out.printf("%s producer ...%n", Thread.currentThread().getId()); + + if (!this.buffer.full()) { + this.buffer.push(new Car()); + System.out.printf( + "%s producer PUSHING IN %s/%s %n", + Thread.currentThread().getId(), + this.buffer.itemCount, + this.buffer.size + ); + } else { + this.asleep.set(true); + } + } + + if (wasEmpty) { + this.wakeCall.set(false); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } }