package pkgData;
public class Counter {
private static final int MAX_TIME = 1000;
private int counter = 0;
public Counter(int counter) {
this.counter = counter;
}
public int getCounter() {
return counter;
}
public synchronized void incCounter() {
try {
long duration = (long) (Math.random() * MAX_TIME);
System.out.println("---------counter: increase counter and do complicated calcultion for " + duration + " msec.");
int temp = counter;
Thread.sleep(duration);
counter = temp + 1;
System.out.println("---------counter: calculation done");
} catch (Exception e) {
System.err.println("counter..." + e.getMessage());
}
}
}
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package pkgMain;
import java.util.ArrayList;
import java.util.concurrent.CyclicBarrier;
import pkgData.Counter;
import pkgSubjects.Worker;
import static pkgSubjects.Worker.NUMBER_OF_WORKERS_FOR_BIGBOX;
/**
*
* @author schueler
*/
public class Main {
/**
* simulation of potato - pickers who
* empties their baskets in big box
* and next 3 workers load big box on the truck
*
* @param args
*/
private static int NUMBER_OF_WORKERS = 5;
private static int DURATION_OF_SHIFT = 15000; //msec
private static Counter boxCounter;
private static ArrayList<Worker> collWorkers = new ArrayList<>();
private static CyclicBarrier cl;
public static void main(String[] args) {
try {
startWorkers();
awaitEndOfShift();
stopWorkers();
printStatistics();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void startWorkers() {
boxCounter = new Counter(0);
long shiftEndTime = System.currentTimeMillis() + DURATION_OF_SHIFT;
cl = new CyclicBarrier(NUMBER_OF_WORKERS_FOR_BIGBOX);
for (int i = 1; i <= NUMBER_OF_WORKERS; i++) {
Worker worker = new Worker("Worker " + i, boxCounter, cl, shiftEndTime);
collWorkers.add(worker);
worker.start();
}
System.out.println("Main...all workers started");
}
private static void stopWorkers() throws InterruptedException {
for (Worker worker : collWorkers) {
worker.interrupt();
}
for (Worker worker : collWorkers) {
worker.join();
}
}
private static void awaitEndOfShift() throws InterruptedException {
System.out.println("Main...waiting end of shift");
Thread.sleep(DURATION_OF_SHIFT);
System.out.println("Main...end of shift");
}
private static void printStatistics() throws InterruptedException {
System.out.println("Main...Worker finished");
System.out.println("Main...box-counter: " + boxCounter.getCounter());
}
}
package pkgSubjects;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import pkgData.Counter;
public class Worker extends Thread {
public static int NUMBER_OF_WORKERS_FOR_BIGBOX = 3;
private static final int MIN_TIME_COLLECTION = 1000;
private static final int MAX_TIME_COLLECTION = 3000;
private String name;
private Counter boxCounter;
private CyclicBarrier barrier;
private long shiftEndTime;
private int round = 0;
private static int waitingWorkers = 0;
public Worker(String name, Counter boxCounter, CyclicBarrier barrier, long shiftEndTime) {
this.name = name;
this.boxCounter = boxCounter;
this.barrier = barrier;
this.shiftEndTime = shiftEndTime;
}
private static synchronized void setWaitingWorkers(int value) {
waitingWorkers = value;
}
private static synchronized int getAndIncrementWaitingWorkers() {
waitingWorkers++;
return waitingWorkers;
}
@Override
public void run() {
try {
while (System.currentTimeMillis() < shiftEndTime) {
round++;
long collectionTime = MIN_TIME_COLLECTION +(long)(Math.random() * (MAX_TIME_COLLECTION - MIN_TIME_COLLECTION));
System.out.println(name + " looking for some potatoes ( round: " + round + ")");
Thread.sleep(collectionTime);
System.out.println(name + " finished collection (" + collectionTime + " msec) => empties his basket into big box");
int waitingCount = getAndIncrementWaitingWorkers();
// Use modulo to handle counter overflow and calculate position in current group
int positionInGroup = (waitingCount - 1) % NUMBER_OF_WORKERS_FOR_BIGBOX;
int needed = NUMBER_OF_WORKERS_FOR_BIGBOX - positionInGroup - 1;
System.out.println(name + " waiting for " + needed + " more mates");
int arrivalIndex = barrier.await();
System.out.println(name + " ** finished waiting (enough workers to lift the box on the truck");
if (arrivalIndex == NUMBER_OF_WORKERS_FOR_BIGBOX - 1) {
System.out.println(name + " ** == starts increasing the boxcounter");
boxCounter.incCounter();
System.out.println(name + " ** == finished increasing the boxcounter");
setWaitingWorkers(0);
}
if (System.currentTimeMillis() < shiftEndTime) {
System.out.println(name + " looking for some potatoes ( round: " + (round + 1) + ")");
}
}
} catch (InterruptedException e) {
} catch (BrokenBarrierException e) {
}
}
}
Das Programm ist grundsätzlich kompilier- und ausführbar. Die Threads starten korrekt, die Worker-Instanzen arbeiten parallel, und der CyclicBarrier-Mechanismus wird verwendet, um jeweils drei Arbeiter zu synchronisieren.
Trotzdem funktioniert die Simulation nicht konsistent bzw. verhält sich unerwartet.
Beobachtete Probleme:
Die Synchronisation zwischen den Threads wirkt unzuverlässig.
Der Zähler (boxCounter) wird nicht immer nachvollziehbar oder erwartungsgemäß erhöht.
Die Verwaltung der wartenden Worker über die statische Variable waitingWorkers führt zu inkonsistentem Verhalten.
Durch das Zurücksetzen von waitingWorkers kann es zu Race Conditions kommen.
Beim Beenden der Schicht (Interrupt) reagieren Threads nicht sauber oder bleiben eventuell in einem Barrier-Wait hängen.
Die Kombination aus CyclicBarrier und zusätzlicher eigener Zähl-Logik (waitingWorkers) wirkt redundant und fehleranfällig.
Zusammengefasst:
Das Programm läuft technisch, aber die Thread-Synchronisation und Gruppenbildung funktionieren logisch nicht stabil. Es treten Nebenläufigkeitsprobleme auf, wodurch das Verhalten nicht deterministisch und teilweise inkorrekt ist.