generated from JavaLabs2025/concurrency-lab1
-
Notifications
You must be signed in to change notification settings - Fork 37
Pozolotin Oleg / Lab-1 / Dining Programmers #7
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
Open
jbisss
wants to merge
11
commits into
JavaLabs2025:master
Choose a base branch
from
JavaLabs2025:feature/dining-programmers
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
607b1a1
add deadline
github-classroom[bot] dafa9a0
[feature] non-beautiful code
jbisss d668330
[feature] some refactor
jbisss 400c24e
[feature] programmer name
jbisss d941046
[feature] removed inner 'test', test needed to be written
jbisss 693b6d4
[feature] getter for programmer's consumed portions of food
jbisss a5beb9c
[feature] some encapsulation
jbisss 5698a7b
[feature] tests
jbisss 85fb381
[fix] bigger delay for thread
jbisss 6c81d35
[fix] lock to atomic
jbisss eff83f4
[fix] take spoons and eating joined actions now
jbisss File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,16 @@ | ||
| package org.labs; | ||
|
|
||
| import org.labs.dining.DiningProgrammersWorld; | ||
|
|
||
| import java.util.Arrays; | ||
|
|
||
| public class Main { | ||
|
|
||
| public static void main(String[] args) { | ||
| System.out.println("Hello, World!"); | ||
| try { | ||
| new DiningProgrammersWorld().startDining(1_000, 3, 7); | ||
| } catch (InterruptedException e) { | ||
| System.out.println("Ooopps... " + Arrays.toString(e.getStackTrace())); | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| package org.labs.dining; | ||
|
|
||
| import org.labs.dining.items.Programmer; | ||
| import org.labs.dining.items.Spoon; | ||
|
|
||
| public class DiningProgrammersWorld { | ||
|
|
||
| private static final int DEFAULT_PORTIONS_AMOUNT = 1_000_000; | ||
| private static final int DEFAULT_WAITERS_AMOUNT = 2; | ||
| private static final int DEFAULT_PROGRAMMERS_AMOUNT = 5; | ||
|
|
||
| private Programmer[] programmers; | ||
|
|
||
| public Programmer[] getProgrammers() { | ||
| return programmers; | ||
| } | ||
|
|
||
| public void startDining( | ||
| Integer portionsAmount, | ||
| Integer waitersAmount, | ||
| Integer programmersAmount | ||
| ) throws InterruptedException { | ||
| int portionsAmountToInitialize = portionsAmount == null ? DEFAULT_PORTIONS_AMOUNT : portionsAmount; | ||
| int waitersAmountToInitialize = waitersAmount == null ? DEFAULT_WAITERS_AMOUNT : waitersAmount; | ||
| int programmersAmountToInitialize = programmersAmount == null ? DEFAULT_PROGRAMMERS_AMOUNT : programmersAmount; | ||
|
|
||
| SharedContext.initialize(portionsAmountToInitialize, waitersAmountToInitialize, programmersAmountToInitialize); | ||
| programmers = new Programmer[programmersAmountToInitialize]; | ||
|
|
||
| for (int i = 0; i < programmersAmountToInitialize; i++) { | ||
| Spoon leftSpoon = SharedContext.getSpoon(i); | ||
| Spoon rightSpoon = SharedContext.getSpoon((i + 1) % programmersAmountToInitialize); | ||
|
|
||
| String programmerName = "Programmer_" + i; | ||
| Programmer currentProgrammer = i == programmersAmountToInitialize - 1 | ||
| ? new Programmer(programmerName, rightSpoon, leftSpoon) | ||
| : new Programmer(programmerName, leftSpoon, rightSpoon); | ||
| currentProgrammer.start(); | ||
| programmers[i] = currentProgrammer; | ||
| } | ||
|
|
||
| for (int i = 0; i < programmersAmountToInitialize; i++) { | ||
| programmers[i].join(); | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| package org.labs.dining; | ||
|
|
||
| import org.labs.dining.items.Spoon; | ||
| import org.labs.dining.items.Waiter; | ||
|
|
||
| import java.util.concurrent.ArrayBlockingQueue; | ||
| import java.util.concurrent.BlockingQueue; | ||
|
|
||
| public class SharedContext { | ||
|
|
||
| private static Waiter[] waiters; | ||
| private static Spoon[] spoons; | ||
| private static BlockingQueue<Waiter> waiterBlockingQueue; | ||
|
|
||
| public static Spoon getSpoon(int atIndex) { | ||
| return spoons[atIndex]; | ||
| } | ||
|
|
||
| public static BlockingQueue<Waiter> getWaiterBlockingQueue() { | ||
| return waiterBlockingQueue; | ||
| } | ||
|
|
||
| public static void initialize( | ||
| int portionsAmount, | ||
| int waitersAmount, | ||
| int spoonsAmount | ||
| ) throws InterruptedException { | ||
| Waiter.setPortionsAmount(portionsAmount); | ||
|
|
||
| SharedContext.waiters = new Waiter[waitersAmount]; | ||
| SharedContext.spoons = new Spoon[spoonsAmount]; | ||
| SharedContext.waiterBlockingQueue = new ArrayBlockingQueue<>(waitersAmount); | ||
|
|
||
| for (int i = 0; i < waitersAmount; i++) { | ||
| SharedContext.waiters[i] = new Waiter(); | ||
| SharedContext.waiterBlockingQueue.put(SharedContext.waiters[i]); | ||
| } | ||
| for (int i = 0; i < spoonsAmount; i++) { | ||
| SharedContext.spoons[i] = new Spoon(); | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| package org.labs.dining.items; | ||
|
|
||
| import org.labs.dining.SharedContext; | ||
|
|
||
| public class Programmer extends Thread { | ||
jbisss marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| private final Spoon leftSpoon; | ||
| private final Spoon rightSpoon; | ||
|
|
||
| private int portionsConsumed = 0; | ||
|
|
||
| public Programmer(String programmerName, Spoon leftSpoon, Spoon rightSpoon) { | ||
| super(programmerName); | ||
| this.leftSpoon = leftSpoon; | ||
| this.rightSpoon = rightSpoon; | ||
| } | ||
|
|
||
| public int getPortionsConsumed() { | ||
| return portionsConsumed; | ||
| } | ||
|
|
||
| /** | ||
| * Любое действие выводится в консоль, поэтому управление "длительностью" действия | ||
| * происходит здесь - в одном месте | ||
| * <p> | ||
| * Выбирается случайное время для задержки, печатается действия и поток "засыпает" на выбранное время | ||
| */ | ||
| private synchronized void printMessage(String message) throws InterruptedException { | ||
| int ms = (int) (Math.random() * 100); | ||
| System.out.println(Thread.currentThread().getName() + " " + message + " for: " + ms + "ms"); | ||
| Thread.sleep(ms); | ||
jbisss marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| public void trashTalk() throws InterruptedException { | ||
| printMessage("is trash-talking"); | ||
| } | ||
|
|
||
| public boolean requestPortion() throws InterruptedException { | ||
| Waiter waiter = SharedContext.getWaiterBlockingQueue().take(); | ||
| boolean portionTaken = waiter.tryTakePortion(); | ||
| SharedContext.getWaiterBlockingQueue().put(waiter); | ||
| return portionTaken; | ||
| } | ||
|
|
||
| public void takeSpoonsAndEat() throws InterruptedException { | ||
| synchronized (leftSpoon) { | ||
| printMessage("takes left spoon"); | ||
| synchronized (rightSpoon) { | ||
| printMessage("takes right spoon"); | ||
| eat(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private void eat() throws InterruptedException { | ||
| printMessage("is eating"); | ||
jbisss marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| this.portionsConsumed++; | ||
| } | ||
|
|
||
| public void putSpoons() throws InterruptedException { | ||
| printMessage("releasing spoons"); | ||
| } | ||
|
|
||
| @Override | ||
| public void run() { | ||
| try { | ||
| while (true) { | ||
jbisss marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| trashTalk(); | ||
| boolean portionTaken = requestPortion(); | ||
| if (!portionTaken) break; | ||
| takeSpoonsAndEat(); | ||
| putSpoons(); | ||
| } | ||
| System.out.println("Done " + this.getName() + " with consumed: " + this.portionsConsumed); | ||
| } catch (InterruptedException e) { | ||
| throw new RuntimeException(e); | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| package org.labs.dining.items; | ||
|
|
||
| public class Spoon { | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package org.labs.dining.items; | ||
|
|
||
| import java.util.concurrent.atomic.AtomicInteger; | ||
|
|
||
| public class Waiter { | ||
|
|
||
| private static AtomicInteger portionsAmount; | ||
|
|
||
| public static void setPortionsAmount(int portionsAmount) { | ||
| Waiter.portionsAmount = new AtomicInteger(portionsAmount); | ||
| } | ||
|
|
||
| public boolean tryTakePortion() { | ||
| int decrementedPortionsAmount = portionsAmount.getAndDecrement(); | ||
| return decrementedPortionsAmount > 0; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| package dining; | ||
|
|
||
| import org.junit.jupiter.api.Test; | ||
| import org.junit.jupiter.params.ParameterizedTest; | ||
| import org.junit.jupiter.params.provider.Arguments; | ||
| import org.junit.jupiter.params.provider.MethodSource; | ||
| import org.labs.dining.DiningProgrammersWorld; | ||
| import org.labs.dining.items.Programmer; | ||
|
|
||
| import java.util.Arrays; | ||
| import java.util.stream.Stream; | ||
|
|
||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
|
||
| public class DiningProgrammersWorldTest { | ||
|
|
||
| private static final int SMALL_PORTIONS_AMOUNT_TO_SIMULATE = 1000; | ||
| private static final int MEDIUM_PORTIONS_AMOUNT_TO_SIMULATE = 10_000; | ||
| private static final int BIG_PORTIONS_AMOUNT_TO_SIMULATE = 100_000; | ||
| private static final int LARGE_PORTIONS_AMOUNT_TO_SIMULATE = 1_000_000; | ||
|
|
||
| private static final int WAITERS_AMOUNT_TO_SIMULATE = 2; | ||
|
|
||
| private static final int PROGRAMMERS_AMOUNT_TO_SIMULATE = 5; | ||
|
|
||
| public record DiningProgrammersWorldArgument(int portionsAmount, int waitersAmount, int programmersAmount){} | ||
|
|
||
| private static Stream<Arguments> provideArguments() { | ||
| return Stream.of( | ||
| Arguments.of(new DiningProgrammersWorldArgument( | ||
| SMALL_PORTIONS_AMOUNT_TO_SIMULATE, | ||
| WAITERS_AMOUNT_TO_SIMULATE, | ||
| PROGRAMMERS_AMOUNT_TO_SIMULATE | ||
| ) | ||
| ), | ||
| Arguments.of(new DiningProgrammersWorldArgument( | ||
| MEDIUM_PORTIONS_AMOUNT_TO_SIMULATE, | ||
| WAITERS_AMOUNT_TO_SIMULATE, | ||
| PROGRAMMERS_AMOUNT_TO_SIMULATE | ||
| ) | ||
| ), | ||
| Arguments.of(new DiningProgrammersWorldArgument( | ||
| BIG_PORTIONS_AMOUNT_TO_SIMULATE, | ||
| WAITERS_AMOUNT_TO_SIMULATE, | ||
| PROGRAMMERS_AMOUNT_TO_SIMULATE | ||
| ) | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| @Test | ||
| public void testNoDeadlocks() throws InterruptedException { | ||
| new DiningProgrammersWorld().startDining( | ||
| LARGE_PORTIONS_AMOUNT_TO_SIMULATE, | ||
| WAITERS_AMOUNT_TO_SIMULATE, | ||
| PROGRAMMERS_AMOUNT_TO_SIMULATE | ||
| ); | ||
| } | ||
|
|
||
| @ParameterizedTest | ||
| @MethodSource("provideArguments") | ||
| public void testNoRaceCondition(DiningProgrammersWorldArgument argument) throws InterruptedException { | ||
| DiningProgrammersWorld diningProgrammersWorld = new DiningProgrammersWorld(); | ||
| diningProgrammersWorld.startDining( | ||
| argument.portionsAmount(), | ||
| argument.waitersAmount(), | ||
| argument.programmersAmount() | ||
| ); | ||
|
|
||
| Programmer[] programmers = diningProgrammersWorld.getProgrammers(); | ||
|
|
||
| int consumedPortionsSum = Arrays.stream(programmers) | ||
| .map(Programmer::getPortionsConsumed) | ||
| .reduce(0, Integer::sum); | ||
|
|
||
| assertEquals(argument.portionsAmount(), consumedPortionsSum); | ||
| } | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Почему вы остановили свой выбор на этой структуре? Как у вас обстоят дела с равномерностью накормленности? Чем она обеспечивается?
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.
Для официантов эта структура была выбрана по той причине, что в моём понимании она достаточно точно описывает модель поведения официантов - программист "забирает" официанта из очереди, чтобы он принёс ему еду, затем официант опять помещается в очередь, готовый, когда будет его время, опять "сходить" за едой
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.
Равномерность накормленности никак не регулируется мной, упустил этот момент...