Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ build/
out/
!**/src/main/**/out/
!**/src/test/**/out/
.idea

### Eclipse ###
.apt_generated
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](https://classroom.github.com/a/qcWcnElX)
# Java concurrency

# Цели и задачи л/р:
Expand Down
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
5 changes: 3 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#Sat Sep 13 12:45:04 MSK 2025
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
47 changes: 32 additions & 15 deletions gradlew
100644 → 100755

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 23 additions & 18 deletions gradlew.bat

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions src/main/java/org/labs/Bowl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.labs;

import java.util.concurrent.atomic.AtomicInteger;

final class Bowl {
// количество ложек супа, оставшихся в миске
final AtomicInteger remaining = new AtomicInteger(0);

// долить в миску новую порцию
void fill(int portion) { remaining.addAndGet(portion); }

// проблем съесть одну ложку
boolean takeOne() {
int cur = remaining.get();
if (cur <= 0) return false;
return remaining.compareAndSet(cur, cur - 1);
}

boolean isEmpty() { return remaining.get() == 0; }
}
14 changes: 14 additions & 0 deletions src/main/java/org/labs/Config.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.labs;

import java.time.Duration;

/**
* @param N number of programmers
* @param W number of waiters
* @param F total portions in stock
* @param thinkMin min thinking time in ms
* @param thinkMax max thinking time in ms
* @param eatMin min eating time in ms
* @param eatMax max eating time in ms
*/
record Config(int N, int W, long F, int bitesInBowl, Duration thinkMin, Duration thinkMax, Duration eatMin, Duration eatMax) {}
101 changes: 101 additions & 0 deletions src/main/java/org/labs/DiningProgrammersSimulation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package org.labs;

import java.io.IOException;
import java.io.InputStream;
import java.time.Duration;
import java.util.Arrays;
import java.util.Properties;
import java.util.concurrent.CyclicBarrier;

public class DiningProgrammersSimulation {
public static SimulationResult runSimulation(Config cfg) throws Exception {
Table table = new Table(cfg);

// барьер для одновременного старта философов
CyclicBarrier startBarrier = new CyclicBarrier(cfg.N());

// официанты
Thread[] waiters = new Thread[cfg.W()];
for (int id = 0; id < cfg.W(); id++) {
waiters[id] = Thread.startVirtualThread(new Waiter(id, table));
}

// программисты
Thread[] programmers = new Thread[cfg.N()];
for (int i = 0; i < cfg.N(); i++) {
final int id = i;
programmers[i] = Thread.startVirtualThread(() -> {
try { startBarrier.await(); } catch (Exception ignored) {}
new Programmer(id, table).run();
});
}

// ждём логического завершения (еда кончилась и миски пусты)
while (true) {
if (table.isFinished()) {
table.closed.set(true);
break;
}
Thread.sleep(10);
}

// корректно завершаем официантов
for (int i = 0; i < cfg.W(); i++) {
table.refillQueue.put(Utils.POISON);
}

// ждём всех
for (Thread t : programmers) t.join();
for (Thread w : waiters) w.join();

return new SimulationResult(table, cfg);
}

private static Config loadConfig() {
Properties props = new Properties();
try (InputStream in = DiningProgrammersSimulation.class
.getClassLoader()
.getResourceAsStream("application.properties")) {

if (in == null) {
throw new RuntimeException("Не найден application.properties в classpath");
}
props.load(in);
} catch (IOException e) {
throw new RuntimeException("Ошибка чтения application.properties", e);
}

int N = Integer.parseInt(props.getProperty("N", "7"));
int W = Integer.parseInt(props.getProperty("W", "3"));
long F = Long.parseLong(props.getProperty("F", "5000"));
int bitesInBowl = Integer.parseInt(props.getProperty("bitesInBowl", "1"));

Duration thinkMin = Duration.ofMillis(Long.parseLong(props.getProperty("thinkMin", "2")));
Duration thinkMax = Duration.ofMillis(Long.parseLong(props.getProperty("thinkMax", "8")));
Duration eatMin = Duration.ofMillis(Long.parseLong(props.getProperty("eatMin", "2")));
Duration eatMax = Duration.ofMillis(Long.parseLong(props.getProperty("eatMax", "6")));

return new Config(N, W, F, bitesInBowl, thinkMin, thinkMax, eatMin, eatMax);
}

public static void main(String[] args) throws Exception {
Config cfg = loadConfig();
SimulationResult res = runSimulation(cfg);

// печать результатов
System.out.println("\n=== RESULT ===");
System.out.printf("Total eaten: %d, stock left: %d (initial %d)%n",
res.totalEaten, res.stockLeft, res.F);
System.out.println("Per programmer portions:");
for (int i = 0; i < res.N; i++) {
System.out.printf(" #%d: %d%n", i, res.eatenPerProgrammer[i]);
}
long max = Arrays.stream(res.eatenPerProgrammer).max().orElse(0);
long min = Arrays.stream(res.eatenPerProgrammer).min().orElse(0);
double avg = res.N == 0 ? 0 : (double) res.totalEaten / res.N;
double spreadPercent = avg == 0 ? 0 : (double)(max - min) / avg * 100.0;
System.out.printf("Min=%d Max=%d Avg=%.2f Spread=%d, SpreadPercent=%.2f%%%n",
min, max, avg, (max - min), spreadPercent);
System.out.println("Finished.");
}
}
7 changes: 0 additions & 7 deletions src/main/java/org/labs/Main.java

This file was deleted.

Loading