-
Notifications
You must be signed in to change notification settings - Fork 37
Лабораторная 1 Хогоев #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,30 @@ | ||
| package org.labs; | ||
|
|
||
| import org.labs.config.AppConfig; | ||
| import org.labs.config.ExecutorType; | ||
| import org.labs.model.Restaurant; | ||
|
|
||
| public class Main { | ||
|
|
||
| public static void main(String[] args) { | ||
| System.out.println("Hello, World!"); | ||
| int numProgrammers = AppConfig.getNumProgrammers(); | ||
| int numWaiters = AppConfig.getNumWaiters(); | ||
| int maxMeals = AppConfig.getMaxMeals(); | ||
| ExecutorType executorType = AppConfig.getExecutorType(); | ||
| Restaurant restaurant = new Restaurant(maxMeals, numProgrammers, numWaiters, executorType); | ||
|
|
||
| long startTime = System.currentTimeMillis(); | ||
| restaurant.startDinner(); | ||
|
|
||
|
|
||
| restaurant.awaitCompletion(); | ||
|
|
||
| long endTime = System.currentTimeMillis(); | ||
| long duration = endTime - startTime; | ||
|
|
||
| restaurant.printStatistics(); | ||
|
|
||
| System.out.println("\nTotal dinner time: " + duration + " ms"); | ||
| System.out.println("Dinner completed successfully!"); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| package org.labs.config; | ||
|
|
||
| import java.io.IOException; | ||
| import java.io.InputStream; | ||
| import java.util.Properties; | ||
|
|
||
| public class AppConfig { | ||
| private static final Properties props = new Properties(); | ||
|
|
||
| static { | ||
| try (InputStream input = AppConfig.class.getClassLoader() | ||
| .getResourceAsStream("config.properties")) { | ||
| if (input == null) { | ||
| System.err.println("Config file not found! Using defaults"); | ||
| setDefaults(); | ||
| } else { | ||
| props.load(input); | ||
| } | ||
| } catch (IOException e) { | ||
| System.err.println("Error loading config: " + e.getMessage()); | ||
| setDefaults(); | ||
| } | ||
| } | ||
|
|
||
| private static void setDefaults() { | ||
| props.setProperty("num.programmers", "7"); | ||
| props.setProperty("num.waiters", "3"); | ||
| props.setProperty("max.meals", "1_000_000"); | ||
| props.setProperty("executor.type", "VIRTUAL_THREADS"); | ||
| } | ||
|
|
||
| public static int getNumProgrammers() { | ||
| return Integer.parseInt(props.getProperty("num.programmers")); | ||
| } | ||
|
|
||
| public static int getNumWaiters() { | ||
| return Integer.parseInt(props.getProperty("num.waiters")); | ||
| } | ||
|
|
||
| public static int getMaxMeals() { | ||
| return Integer.parseInt(props.getProperty("max.meals")); | ||
| } | ||
|
|
||
| public static ExecutorType getExecutorType() { | ||
| try { | ||
| return ExecutorType.valueOf(props.getProperty("executor.type").toUpperCase()); | ||
| } catch (IllegalArgumentException e) { | ||
| System.err.println("Invalid executor type in config, using VIRTUAL_THREADS"); | ||
| return ExecutorType.VIRTUAL_THREADS; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package org.labs.config; | ||
|
|
||
| public enum ExecutorType { | ||
| VIRTUAL_THREADS, | ||
| FIXED_THREAD_POOL, | ||
| CACHED_THREAD_POOL, | ||
| WORK_STEALING_POOL, | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| package org.labs.model; | ||
|
|
||
| import java.util.concurrent.atomic.AtomicInteger; | ||
|
|
||
| public class Kitchen { | ||
| private final AtomicInteger remainingMeals; | ||
| private volatile boolean isOpen = true; | ||
|
|
||
| public Kitchen(int totalMeals) { | ||
| this.remainingMeals = new AtomicInteger(totalMeals); | ||
| } | ||
|
|
||
| public boolean tryTakeMeal() { | ||
| return remainingMeals.getAndUpdate(current -> current > 0 ? current - 1 : current) > 0; | ||
| } | ||
|
|
||
| public boolean hasMeals() { | ||
| return remainingMeals.get() > 0 && isOpen; | ||
| } | ||
|
|
||
| public int getRemainingMeals() { | ||
| return remainingMeals.get(); | ||
| } | ||
|
|
||
| public void close() { | ||
| isOpen = false; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| package org.labs.model; | ||
|
|
||
| import java.util.Comparator; | ||
| import java.util.concurrent.ThreadLocalRandom; | ||
| import java.util.concurrent.atomic.AtomicBoolean; | ||
| import java.util.concurrent.atomic.AtomicInteger; | ||
|
|
||
| class Programmer implements Runnable { | ||
| private final int id; | ||
| private final Spoon firstSpoon; | ||
| private final Spoon secondSpoon; | ||
| private final Waiter waiter; | ||
| private final AtomicInteger mealsEaten = new AtomicInteger(0); | ||
| private final AtomicBoolean permissionToEat = new AtomicBoolean(false); | ||
| private volatile boolean running = true; | ||
|
|
||
| public Programmer(int id, Spoon leftSpoon, Spoon rightSpoon, Waiter waiter) { | ||
| this.id = id; | ||
| this.waiter = waiter; | ||
|
|
||
| // Определяем порядок взятия ложек для избежания deadlock | ||
| if (leftSpoon.getId() < rightSpoon.getId()) { | ||
| this.firstSpoon = leftSpoon; | ||
| this.secondSpoon = rightSpoon; | ||
| } else { | ||
| this.firstSpoon = rightSpoon; | ||
| this.secondSpoon = leftSpoon; | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public void run() { | ||
| try { | ||
| while (running && waiter.isKitchenOpen()) { | ||
| think(); | ||
| requestToEat(); | ||
| } | ||
| } catch (InterruptedException e) { | ||
| Thread.currentThread().interrupt(); | ||
| } finally { | ||
| System.out.println("Programmer " + id + " finished. Eaten: " + mealsEaten.get() + " meals"); | ||
| } | ||
| } | ||
|
|
||
| private void think() throws InterruptedException { | ||
| System.out.println("Programmer " + id + " is thinking"); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Как будто они у вас думают мгновенно. См. коммент про время приема пищи |
||
| Thread.sleep(ThreadLocalRandom.current().nextInt(100, 200)); | ||
| } | ||
|
|
||
| private void requestToEat() throws InterruptedException { | ||
| if (!running || !waiter.isKitchenOpen()) { | ||
| return; | ||
| } | ||
|
|
||
| permissionToEat.set(false); | ||
| waiter.placeOrder(this); | ||
|
|
||
| synchronized (this) { | ||
| if (!permissionToEat.get()) { | ||
| wait(5000); // Долгий таймаут, просто чтобы не блокировать навсегда | ||
| } | ||
| } | ||
|
|
||
| if (permissionToEat.get() && running) { | ||
| eat(); | ||
| } | ||
| } | ||
|
|
||
| private void eat() throws InterruptedException { | ||
| System.out.println("Programmer " + id + " has food, waiting for spoons..."); | ||
|
|
||
| firstSpoon.acquire(); | ||
| try { | ||
| secondSpoon.acquire(); | ||
|
|
||
| Thread.sleep(ThreadLocalRandom.current().nextInt(100, 200)); | ||
| try { | ||
| System.out.println("Programmer " + id + " is eating (" + (mealsEaten.get() + 1) + " meal)"); | ||
| mealsEaten.incrementAndGet(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Если я правильно понял, то они у вас едят мгновенно. Попробуйте добавть слип на случайное время, или каждый программист ест за свое какое то время константное, не важно, главное чтобы не у всех было одинаковое |
||
| System.out.println("Programmer " + id + " finished eating"); | ||
| } finally { | ||
| secondSpoon.release(); | ||
| } | ||
| } finally { | ||
| firstSpoon.release(); | ||
| } | ||
| } | ||
|
|
||
| public void receiveMeal() { | ||
| permissionToEat.set(true); | ||
| synchronized (this) { | ||
| notify(); | ||
| } | ||
| } | ||
|
|
||
| public void stop() { | ||
| running = false; | ||
| synchronized (this) { | ||
| notifyAll(); | ||
| } | ||
| } | ||
|
|
||
| public static Comparator<Programmer> getMealsEatenComparator() { | ||
| return Comparator.comparingInt(Programmer::getMealsEaten); | ||
| } | ||
|
|
||
| public int getMealsEaten() { return mealsEaten.get(); } | ||
| public void setPermissionToEat(boolean permission) { permissionToEat.set(permission); } | ||
| public int getId() { return id; } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Понимаю, что вы потестили через мейн. Но чисто по условиям таски -- сделайте пж несколько тестов. Можно в качестве ассертов проверять равномерность накормленности. А так достаточно тестов на успешное выполнение для нескольких конфигураций