diff --git a/src/pp.04.01-RunnableReturn/README.md b/src/pp.04.01-RunnableReturn/README.md
new file mode 100644
index 0000000..3fa85f7
--- /dev/null
+++ b/src/pp.04.01-RunnableReturn/README.md
@@ -0,0 +1,7 @@
+# Laboraufgabe "Thread für ``Runnable`` mit Rückgabewert"
+- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/04-01-RunnableWithResult.html)
+- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/04-Solutions.html#laboraufgabe-thread-für-runnable-mit-rückgabewert)
+
+# Materialien
+- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/04-threadpools.html)
+- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/04-threadpools.html)
diff --git a/src/pp.04.01-RunnableReturn_solution/README.md b/src/pp.04.01-RunnableReturn_solution/README.md
new file mode 100644
index 0000000..3fa85f7
--- /dev/null
+++ b/src/pp.04.01-RunnableReturn_solution/README.md
@@ -0,0 +1,7 @@
+# Laboraufgabe "Thread für ``Runnable`` mit Rückgabewert"
+- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/04-01-RunnableWithResult.html)
+- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/04-Solutions.html#laboraufgabe-thread-für-runnable-mit-rückgabewert)
+
+# Materialien
+- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/04-threadpools.html)
+- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/04-threadpools.html)
diff --git a/src/pp.04.02-Future/README.md b/src/pp.04.02-Future/README.md
new file mode 100644
index 0000000..bd2c085
--- /dev/null
+++ b/src/pp.04.02-Future/README.md
@@ -0,0 +1,7 @@
+# Laboraufgabe "Asynchrone Ausführung mit ``Callable`` und ``Future``"
+- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/04-02-Future.html)
+- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/04-Solutions.html#laboraufgabe-asynchrone-ausführung-mit-callable-und-future)
+
+# Materialien
+- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/04-threadpools.html)
+- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/04-threadpools.html)
diff --git a/src/pp.04.02-Future_solution/README.md b/src/pp.04.02-Future_solution/README.md
new file mode 100644
index 0000000..bd2c085
--- /dev/null
+++ b/src/pp.04.02-Future_solution/README.md
@@ -0,0 +1,7 @@
+# Laboraufgabe "Asynchrone Ausführung mit ``Callable`` und ``Future``"
+- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/04-02-Future.html)
+- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/04-Solutions.html#laboraufgabe-asynchrone-ausführung-mit-callable-und-future)
+
+# Materialien
+- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/04-threadpools.html)
+- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/04-threadpools.html)
diff --git a/src/pp.04.03-ThreadPoolSize/README.md b/src/pp.04.03-ThreadPoolSize/README.md
new file mode 100644
index 0000000..3a03d3a
--- /dev/null
+++ b/src/pp.04.03-ThreadPoolSize/README.md
@@ -0,0 +1,7 @@
+# Laboraufgabe "Thread Pools"
+- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/04-03-ThreadPoolSize.html)
+- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/04-Solutions.html#laboraufgabe-thread-pools)
+
+# Materialien
+- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/04-threadpools.html)
+- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/04-threadpools.html)
diff --git a/src/pp.04.03-ThreadPoolSize_solution/README.md b/src/pp.04.03-ThreadPoolSize_solution/README.md
new file mode 100644
index 0000000..3a03d3a
--- /dev/null
+++ b/src/pp.04.03-ThreadPoolSize_solution/README.md
@@ -0,0 +1,7 @@
+# Laboraufgabe "Thread Pools"
+- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/04-03-ThreadPoolSize.html)
+- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/04-Solutions.html#laboraufgabe-thread-pools)
+
+# Materialien
+- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/04-threadpools.html)
+- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/04-threadpools.html)
diff --git a/src/pp.05.01-CounterAtomic/README.md b/src/pp.05.01-CounterAtomic/README.md
new file mode 100644
index 0000000..ec96a93
--- /dev/null
+++ b/src/pp.05.01-CounterAtomic/README.md
@@ -0,0 +1,7 @@
+# Laboraufgabe "Counter mit Atomics threadsicher machen"
+- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/05-01-CounterAtomic.html)
+- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/05-Solutions.html#laboraufgabe-counter-mit-atomics-threadsicher-machen)
+
+# Materialien
+- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/05-atomics.html)
+- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/05-atomics.html)
diff --git a/src/pp.05.01-CounterAtomic/justfile b/src/pp.05.01-CounterAtomic/justfile
new file mode 100644
index 0000000..43d3962
--- /dev/null
+++ b/src/pp.05.01-CounterAtomic/justfile
@@ -0,0 +1,12 @@
+default:
+ mvn clean compile test
+exec args:
+ mvn exec:java -Dexec.args={{args}}
+clean:
+ mvn clean
+compile:
+ mvn compile
+test:
+ mvn test
+javadoc:
+ mvn javadoc:javadoc
diff --git a/src/pp.05.01-CounterAtomic/pom.xml b/src/pp.05.01-CounterAtomic/pom.xml
new file mode 100644
index 0000000..29d7273
--- /dev/null
+++ b/src/pp.05.01-CounterAtomic/pom.xml
@@ -0,0 +1,60 @@
+
+ 4.0.0
+ pp
+ pp.05.01-CounterAtomic
+ 1.0-SNAPSHOT
+ jar
+
+
+ 10
+ UTF-8
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.10.0
+ test
+
+
+ org.projectlombok
+ lombok
+ 1.18.30
+ provided
+
+
+ net.jcip
+ jcip-annotations
+ 1.0
+ provided
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.0.0
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.9.0
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 3.1.0
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.5.0
+
+ private
+ en_US
+
+
+
+
+
diff --git a/src/pp.05.01-CounterAtomic/src/main/java/pp/Counter.java b/src/pp.05.01-CounterAtomic/src/main/java/pp/Counter.java
new file mode 100644
index 0000000..ce619a1
--- /dev/null
+++ b/src/pp.05.01-CounterAtomic/src/main/java/pp/Counter.java
@@ -0,0 +1,22 @@
+package pp;
+
+class Counter {
+ private int c;
+
+ public Counter(int init) {
+ this.c = init;
+ }
+
+ public void inc() {
+ this.c++;
+ }
+
+ public void dec() {
+ this.c--;
+ }
+
+ public int get() {
+ return this.c;
+ }
+
+}
diff --git a/src/pp.05.01-CounterAtomic/src/test/java/pp/CounterTest.java b/src/pp.05.01-CounterAtomic/src/test/java/pp/CounterTest.java
new file mode 100644
index 0000000..79102d2
--- /dev/null
+++ b/src/pp.05.01-CounterAtomic/src/test/java/pp/CounterTest.java
@@ -0,0 +1,19 @@
+package pp;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+public class CounterTest {
+
+ @Test
+ public void testInc() throws InterruptedException {
+ fail();
+ }
+
+ @Test
+ public void testDec() throws InterruptedException {
+ fail();
+ }
+
+}
diff --git a/src/pp.05.01-CounterAtomic_solution/README.md b/src/pp.05.01-CounterAtomic_solution/README.md
new file mode 100644
index 0000000..ec96a93
--- /dev/null
+++ b/src/pp.05.01-CounterAtomic_solution/README.md
@@ -0,0 +1,7 @@
+# Laboraufgabe "Counter mit Atomics threadsicher machen"
+- [Aufgabenstellung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/05-01-CounterAtomic.html)
+- [Musterlösung](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/labs/05-Solutions.html#laboraufgabe-counter-mit-atomics-threadsicher-machen)
+
+# Materialien
+- [Folien](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/slides/05-atomics.html)
+- [Skript](https://services.informatik.hs-mannheim.de/~s.leuchter/pp/notes/05-atomics.html)
diff --git a/src/pp.05.01-CounterAtomic_solution/justfile b/src/pp.05.01-CounterAtomic_solution/justfile
new file mode 100644
index 0000000..43d3962
--- /dev/null
+++ b/src/pp.05.01-CounterAtomic_solution/justfile
@@ -0,0 +1,12 @@
+default:
+ mvn clean compile test
+exec args:
+ mvn exec:java -Dexec.args={{args}}
+clean:
+ mvn clean
+compile:
+ mvn compile
+test:
+ mvn test
+javadoc:
+ mvn javadoc:javadoc
diff --git a/src/pp.05.01-CounterAtomic_solution/pom.xml b/src/pp.05.01-CounterAtomic_solution/pom.xml
new file mode 100644
index 0000000..2b5d6c9
--- /dev/null
+++ b/src/pp.05.01-CounterAtomic_solution/pom.xml
@@ -0,0 +1,60 @@
+
+ 4.0.0
+ pp
+ pp.05.01-CounterAtomic_solution
+ 1.0-SNAPSHOT
+ jar
+
+
+ 10
+ UTF-8
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.10.0
+ test
+
+
+ org.projectlombok
+ lombok
+ 1.18.30
+ provided
+
+
+ net.jcip
+ jcip-annotations
+ 1.0
+ provided
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.0.0
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.9.0
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 3.1.0
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.5.0
+
+ private
+ en_US
+
+
+
+
+
diff --git a/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/AtomicCounter1.java b/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/AtomicCounter1.java
new file mode 100644
index 0000000..4d098bc
--- /dev/null
+++ b/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/AtomicCounter1.java
@@ -0,0 +1,32 @@
+package pp;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+class AtomicCounter1 implements ICounter {
+ private final AtomicInteger c;
+
+ public AtomicCounter1(int init) {
+ this.c = new AtomicInteger(init);
+ }
+
+ @Override
+ public void inc() {
+ var temp = this.c.get();
+ while (!this.c.compareAndSet(temp, temp + 1)) {
+ temp = this.c.get();
+ }
+ }
+
+ @Override
+ public void dec() {
+ var temp = this.c.get();
+ while (!this.c.compareAndSet(temp, temp - 1)) {
+ temp = this.c.get();
+ }
+ }
+
+ @Override
+ public int get() {
+ return this.c.get();
+ }
+}
diff --git a/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/AtomicCounter2.java b/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/AtomicCounter2.java
new file mode 100644
index 0000000..8aecd91
--- /dev/null
+++ b/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/AtomicCounter2.java
@@ -0,0 +1,26 @@
+package pp;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+class AtomicCounter2 implements ICounter {
+ private final AtomicInteger c;
+
+ public AtomicCounter2(int init) {
+ this.c = new AtomicInteger(init);
+ }
+
+ @Override
+ public void inc() {
+ this.c.incrementAndGet();
+ }
+
+ @Override
+ public void dec() {
+ this.c.decrementAndGet();
+ }
+
+ @Override
+ public int get() {
+ return this.c.get();
+ }
+}
diff --git a/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/AtomicCounter3.java b/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/AtomicCounter3.java
new file mode 100644
index 0000000..18b58cf
--- /dev/null
+++ b/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/AtomicCounter3.java
@@ -0,0 +1,38 @@
+package pp;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+class AtomicCounter3 implements ICounter {
+ private final AtomicInteger c;
+
+ public AtomicCounter3(int init) {
+ this.c = new AtomicInteger(init);
+ }
+
+ @Override
+ public void inc() {
+ for (;;) {
+ var current = this.c.get();
+ var next = current + 1;
+ if (this.c.compareAndSet(current, next)) {
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void dec() {
+ for (;;) {
+ var current = this.c.get();
+ var next = current - 1;
+ if (this.c.compareAndSet(current, next)) {
+ break;
+ }
+ }
+ }
+
+ @Override
+ public int get() {
+ return this.c.get();
+ }
+}
diff --git a/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/AtomicCounter4.java b/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/AtomicCounter4.java
new file mode 100644
index 0000000..04b3206
--- /dev/null
+++ b/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/AtomicCounter4.java
@@ -0,0 +1,26 @@
+package pp;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+class AtomicCounter4 implements ICounter {
+ private final AtomicInteger c;
+
+ public AtomicCounter4(int init) {
+ this.c = new AtomicInteger(init);
+ }
+
+ @Override
+ public void inc() {
+ this.c.updateAndGet(i -> i + 1);
+ }
+
+ @Override
+ public void dec() {
+ this.c.updateAndGet(i -> i - 1);
+ }
+
+ @Override
+ public int get() {
+ return this.c.get();
+ }
+}
diff --git a/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/Counter.java b/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/Counter.java
new file mode 100644
index 0000000..fc83ae7
--- /dev/null
+++ b/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/Counter.java
@@ -0,0 +1,24 @@
+package pp;
+
+class Counter implements ICounter {
+ private int c;
+
+ public Counter(int init) {
+ this.c = init;
+ }
+
+ @Override
+ public void inc() {
+ this.c++;
+ }
+
+ @Override
+ public void dec() {
+ this.c--;
+ }
+
+ @Override
+ public int get() {
+ return this.c;
+ }
+}
diff --git a/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/ICounter.java b/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/ICounter.java
new file mode 100644
index 0000000..18b4caa
--- /dev/null
+++ b/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/ICounter.java
@@ -0,0 +1,11 @@
+package pp;
+
+interface ICounter {
+
+ void inc();
+
+ void dec();
+
+ int get();
+
+}
diff --git a/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/SynchronizedCounter.java b/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/SynchronizedCounter.java
new file mode 100644
index 0000000..050cf46
--- /dev/null
+++ b/src/pp.05.01-CounterAtomic_solution/src/main/java/pp/SynchronizedCounter.java
@@ -0,0 +1,24 @@
+package pp;
+
+class SynchronizedCounter implements ICounter {
+ private int c;
+
+ public SynchronizedCounter(int init) {
+ this.c = init;
+ }
+
+ @Override
+ public synchronized void inc() {
+ this.c++;
+ }
+
+ @Override
+ public synchronized void dec() {
+ this.c--;
+ }
+
+ @Override
+ public synchronized int get() {
+ return this.c;
+ }
+}
diff --git a/src/pp.05.01-CounterAtomic_solution/src/test/java/pp/CounterTest.java b/src/pp.05.01-CounterAtomic_solution/src/test/java/pp/CounterTest.java
new file mode 100644
index 0000000..c791d09
--- /dev/null
+++ b/src/pp.05.01-CounterAtomic_solution/src/test/java/pp/CounterTest.java
@@ -0,0 +1,116 @@
+package pp;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+class CounterTest {
+ private final static int RUNS = 500000;
+
+ private static void testIncrement(ICounter counter) {
+ assertEquals(0, counter.get());
+ var t1 = new Thread(() -> {
+ for (var j = 0; j < RUNS; j++) {
+ counter.inc();
+ }
+ });
+ var t2 = new Thread(() -> {
+ for (var j = 0; j < RUNS; j++) {
+ counter.inc();
+ }
+ });
+ t1.start();
+ t2.start();
+ try {
+ t1.join();
+ t2.join();
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ }
+ assertEquals(RUNS * 2, counter.get());
+ }
+
+ @Test
+ void testCounterIncrement() throws InterruptedException {
+ testIncrement(new Counter(0));
+ }
+
+ @Test
+ void testSynchronizedCounterIncrement() throws InterruptedException {
+ testIncrement(new SynchronizedCounter(0));
+ }
+
+ @Test
+ void testAtomicCounter1Increment() throws InterruptedException {
+ testIncrement(new AtomicCounter1(0));
+ }
+
+ @Test
+ void testAtomicCounter2Increment() throws InterruptedException {
+ testIncrement(new AtomicCounter2(0));
+ }
+
+ @Test
+ void testAtomicCounter3Increment() throws InterruptedException {
+ testIncrement(new AtomicCounter3(0));
+ }
+
+ @Test
+ void testAtomicCounter4Increment() throws InterruptedException {
+ testIncrement(new AtomicCounter4(0));
+ }
+
+ private static void testDecrement(ICounter counter) {
+ assertEquals(RUNS * 2, counter.get());
+ var t1 = new Thread(() -> {
+ for (var j = 0; j < RUNS; j++) {
+ counter.dec();
+ }
+ });
+ var t2 = new Thread(() -> {
+ for (var j = 0; j < RUNS; j++) {
+ counter.dec();
+ }
+ });
+ t1.start();
+ t2.start();
+ try {
+ t1.join();
+ t2.join();
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ }
+ assertEquals(0, counter.get());
+ }
+
+ @Test
+ void testCounterDecrement() throws InterruptedException {
+ testDecrement(new Counter(RUNS * 2));
+ }
+
+ @Test
+ void testSynchronizedCounterDecrement() throws InterruptedException {
+ testDecrement(new SynchronizedCounter(RUNS * 2));
+ }
+
+ @Test
+ void testAtomicCounter1Decrement() throws InterruptedException {
+ testDecrement(new AtomicCounter1(RUNS * 2));
+ }
+
+ @Test
+ void testAtomicCounter2Decrement() throws InterruptedException {
+ testDecrement(new AtomicCounter2(RUNS * 2));
+ }
+
+ @Test
+ void testAtomicCounter3Decrement() throws InterruptedException {
+ testDecrement(new AtomicCounter3(RUNS * 2));
+ }
+
+ @Test
+ void testAtomicCounter4Decrement() throws InterruptedException {
+ testDecrement(new AtomicCounter4(RUNS * 2));
+ }
+
+}