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 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
71 changes: 71 additions & 0 deletions src/main/java/org/labs/lab1/Developer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.labs.lab1;

import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadLocalRandom;

public class Developer implements Comparable<Developer>, Runnable {

private final int id;
private final Spoon leftSpoon;
private final Spoon rightSpoon;
private final BlockingQueue<Developer> hungryDevs;
private int eaten = 0;

public Developer(int id, Spoon leftSpoon, Spoon rightSpoon, BlockingQueue<Developer> hungryDevs) {
this.id = id;
this.leftSpoon = leftSpoon;
this.rightSpoon = rightSpoon;
this.hungryDevs = hungryDevs;
}

@Override
public void run() {
while (Lunch.REMAINING_FOOD.get() > 0) {
try {
Thread.sleep(ThreadLocalRandom.current().nextInt(20, 60));
} catch (InterruptedException e) {
System.out.println("Программиста " + id + " прервали на обсуждении.");
return;
}

hungryDevs.add(this);
}
}

public void eat() {
Spoon first = leftSpoon;
Spoon second = rightSpoon;
if (first.id() > second.id()) {
Spoon tmp = first;
first = second;
second = tmp;
}

try {
synchronized (first) {
synchronized (second) {
eaten++;
System.out.println("Программист " + id + ". Всего съел: " + eaten);
Thread.sleep(ThreadLocalRandom.current().nextInt(60, 140));
}
}
} catch (InterruptedException e) {
System.out.println("Программиста " + id + " прервали на поедании блюда #" + eaten);
return;
}

System.out.println("Программист " + id + " закончил обед. Съел порций: " + eaten);
}

@Override
public int compareTo(Developer o) {
if (this.eaten > o.eaten) {
return 1;
} else if (this.eaten < o.eaten) {
return -1;
} else {
return 0;
}
}
}
94 changes: 94 additions & 0 deletions src/main/java/org/labs/lab1/Lunch.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package org.labs.lab1;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

import org.labs.Main;

public class Lunch {

public static AtomicInteger REMAINING_FOOD;
public static BlockingQueue<Developer> KITCHEN;

public static void main(String[] args) {
Properties prop = new Properties();

try (InputStream input = Main.class.getClassLoader().getResourceAsStream("application.properties")) {
if (input == null) {
System.out.println("Файл application.properties не найден в ресурсах!");
return;
}
prop.load(input);
} catch (FileNotFoundException e) {
System.out.println("Файл не найден");
} catch (IOException e) {
System.out.println(e.getMessage());
System.out.println("Проблемы ввода/вывода");
}

int devCount = Integer.parseInt(prop.getProperty("devCount", "7"));
int waiterCount = Integer.parseInt(prop.getProperty("waiterCount", "2"));
int totalFood = Integer.parseInt(prop.getProperty("totalFood", "1000"));
String threadPoolTypeStr = prop.getProperty("threadPoolType", "SINGLE");
ThreadPoolType threadPoolType = ThreadPoolType.valueOf(threadPoolTypeStr);

Lunch lunch = new Lunch();
lunch.startLunch(devCount, waiterCount, totalFood, threadPoolType);
}

private void startLunch(int devCount, int waiterCount, int totalFood, ThreadPoolType threadPoolType) {
REMAINING_FOOD = new AtomicInteger(totalFood);
KITCHEN = new PriorityBlockingQueue<>(devCount);

ExecutorService executorService = switch (threadPoolType) {
case FIXED -> Executors.newFixedThreadPool(devCount + waiterCount);
case CACHED -> Executors.newCachedThreadPool();
case WORK_STEALING -> Executors.newWorkStealingPool(devCount + waiterCount);
case SINGLE -> Executors.newSingleThreadExecutor();
};

long start = System.currentTimeMillis();

Waiter[] waiters = new Waiter[waiterCount];
for (int i = 0; i < waiterCount; i++) {
waiters[i] = new Waiter(i, KITCHEN);
executorService.execute(waiters[i]);
}

Developer[] devs = getDevs(devCount);
for (Developer dev : devs) {
executorService.execute(dev);
}

executorService.shutdown();
try {
executorService.awaitTermination(5, TimeUnit.MINUTES);
} catch (InterruptedException e) {
System.out.println("Ожидание окончания работы было прервано");
}

long workingTime = System.currentTimeMillis() - start;
System.out.println(threadPoolType + " thread pool отработал за " + workingTime + " мс");
}

private static Developer[] getDevs(int devCount) {
Developer[] devs = new Developer[devCount];

Spoon[] spoons = new Spoon[devCount];
for (int i = 0; i < devCount; i++) {
spoons[i] = new Spoon(i);
}

for (int i = 0; i < devCount; i++) {
Spoon left = spoons[i];
Spoon right = spoons[(i + 1) % devCount];
devs[i] = new Developer(i, left, right, KITCHEN);
}

return devs;
}
}
4 changes: 4 additions & 0 deletions src/main/java/org/labs/lab1/Spoon.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package org.labs.lab1;

public record Spoon(int id) {
}
8 changes: 8 additions & 0 deletions src/main/java/org/labs/lab1/ThreadPoolType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.labs.lab1;

public enum ThreadPoolType {
FIXED,
CACHED,
WORK_STEALING,
SINGLE
}
31 changes: 31 additions & 0 deletions src/main/java/org/labs/lab1/Waiter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.labs.lab1;
import java.util.concurrent.BlockingQueue;

public class Waiter implements Runnable {

private final int id;
private final BlockingQueue<Developer> hungryDevs;

public Waiter(int id, BlockingQueue<Developer> hungryDevs) {
this.id = id;
this.hungryDevs = hungryDevs;
}

@Override
public void run() {
int next = Lunch.REMAINING_FOOD.getAndDecrement();

while (next > 0) {
try {
Developer hungryDev = hungryDevs.take();
hungryDev.eat();
} catch (InterruptedException e) {
System.out.println("Вставка официантом " + id + " блюда #" + next + " была прервана");
Thread.currentThread().interrupt();
return;
}

next = Lunch.REMAINING_FOOD.getAndDecrement();
}
}
}
4 changes: 4 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
devCount=7
waiterCount=2
totalFood=1000
threadPoolType=WORK_STEALING