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