Skip to content
Open

Lab2 #64

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
114 changes: 114 additions & 0 deletions lab-02/by/nrydo/docks_and_hobos/ConfigReader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package by.nrydo.docks_and_hobos;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;

import java.io.FileReader;
import java.util.Arrays;

public class ConfigReader {
private static ConfigReader instance = null;

private int generatingTime;
private int shipCapacityMin;
private int shipCapacityMax;
private String[] cargoTypes;
private int maxShips;
private int unloadingSpeed;
private int dockCapacity;
private int hobos;
private int[] ingredientsCount;
private int stealingTime;
private int eatingTime;

private ConfigReader() {
}

public static ConfigReader getInstance() {
if (instance == null) {
instance = new ConfigReader();
}
return instance;
}

public void readConfig(String filePath) {
JSONParser parser = new JSONParser();

try (FileReader reader = new FileReader(filePath)) {
Object obj = parser.parse(reader);
JSONObject jsonObject = (JSONObject) obj;

generatingTime = Math.toIntExact((Long) jsonObject.get("generating_time"));
shipCapacityMin = Math.toIntExact((Long) jsonObject.get("ship_capacity_min"));
shipCapacityMax = Math.toIntExact((Long) jsonObject.get("ship_capacity_max"));

JSONArray cargoTypesJson = (JSONArray) jsonObject.get("cargo_types");
cargoTypes = new String[cargoTypesJson.size()];
for (int i = 0; i < cargoTypesJson.size(); i++) {
cargoTypes[i] = (String) cargoTypesJson.get(i);
}

maxShips = Math.toIntExact((Long) jsonObject.get("max_ships"));
unloadingSpeed = Math.toIntExact((Long) jsonObject.get("unloading_speed"));
dockCapacity = Math.toIntExact((Long) jsonObject.get("dock_capacity"));
hobos = Math.toIntExact((Long) jsonObject.get("hobos"));

JSONArray ingredientsCountJson = (JSONArray) jsonObject.get("ingredients_count");
ingredientsCount = new int[cargoTypesJson.size()];
for (int i = 0; i < ingredientsCountJson.size(); i++) {
ingredientsCount[i] = ((Long) ingredientsCountJson.get(i)).intValue();
}

stealingTime = Math.toIntExact((Long) jsonObject.get("stealing_time"));
eatingTime = Math.toIntExact((Long) jsonObject.get("eating_time"));

} catch (Exception e) {
e.printStackTrace();
}
}

public int getGeneratingTime() {
return generatingTime;
}

public int getShipCapacityMin() {
return shipCapacityMin;
}

public int getShipCapacityMax() {
return shipCapacityMax;
}

public String[] getCargoTypes() {
return cargoTypes;
}

public int getMaxShips() {
return maxShips;
}

public int getUnloadingSpeed() {
return unloadingSpeed;
}

public int getDockCapacity() {
return dockCapacity;
}

public int getHobos() {
return hobos;
}

public int[] getIngredientsCount() {
return ingredientsCount;
}

public int getStealingTime() {
return stealingTime;
}

public int getEatingTime() {
return eatingTime;
}
}
107 changes: 107 additions & 0 deletions lab-02/by/nrydo/docks_and_hobos/Dock.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package by.nrydo.docks_and_hobos;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

public class Dock implements Runnable {
private final int unloadingSpeed;
private final int dockCapacity;
private final int[] currentCargoStore;
private final Tunnel tunnel;
private final int maxBatchCount = 1;
private final Semaphore cargoSemaphore;
private final Lock stealingLock;
private int unloadThisSecond;
private int unloadBatchCount;
private final Logger logger;

public Dock(Tunnel tunnel) {
this.tunnel = tunnel;
unloadingSpeed = ConfigReader.getInstance().getUnloadingSpeed();
dockCapacity = ConfigReader.getInstance().getDockCapacity();
currentCargoStore = new int[ConfigReader.getInstance().getCargoTypes().length];
cargoSemaphore = new Semaphore(0);
stealingLock = new ReentrantLock();
unloadThisSecond = 0;
unloadBatchCount = 0;
logger = createLogger();
}

private Logger createLogger() {
Logger logger = Logger.getLogger(Dock.class.getName());
try {
FileHandler fileHandler = new FileHandler("log/dock.log");
fileHandler.setFormatter(new SimpleFormatter());
logger.addHandler(fileHandler);
} catch (Exception e) {
logger.log(Level.SEVERE, "Failed to create logger", e);
}
return logger;
}

@Override
public void run() {
while (true) {
Ship ship = tunnel.getShip();
unloadCargo(ship);
}
}

public int steal() {
try {
cargoSemaphore.acquire();
stealingLock.lock();
List<Integer> cargos = new ArrayList<>();
for (int i = 0; i < currentCargoStore.length; i++) {
if (currentCargoStore[i] > 0) {
cargos.add(i);
}
}
int cargo = cargos.get((new Random()).nextInt(cargos.size()));
currentCargoStore[cargo]--;
stealingLock.unlock();
return cargo;
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}

private void unloadCargo(Ship ship) {
while (ship.getStore() > 0) {
try {
int cargo = currentCargoStore[ship.getCargoType()];
int batchSize = ship.take(getBatchSize());
int cargoToUnload = Math.min(batchSize, dockCapacity - cargo);
cargoSemaphore.release(batchSize);
currentCargoStore[ship.getCargoType()] = cargo + cargoToUnload;
logCargoUnloading(cargoToUnload, ConfigReader.getInstance().getCargoTypes()[ship.getCargoType()]);
Thread.sleep(999L / maxBatchCount + 1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}

private int getBatchSize() {
if (unloadBatchCount == 0) {
unloadBatchCount = maxBatchCount;
unloadThisSecond = unloadingSpeed;
}
int result = (unloadThisSecond + unloadBatchCount / 2) / unloadBatchCount;
unloadThisSecond -= result;
unloadBatchCount--;
return result;
}

private void logCargoUnloading(int cargoToUnload, String cargoType) {
logger.info(String.format("Unloaded cargo: quantity=%d, type=%s", cargoToUnload, cargoType));
}
}
105 changes: 105 additions & 0 deletions lab-02/by/nrydo/docks_and_hobos/Hobo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package by.nrydo.docks_and_hobos;

import java.util.Arrays;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

public class Hobo implements Runnable {
private boolean isCook = false;
private Semaphore cookSemaphore;
private Semaphore eatingSemaphore;
private Lock ingredientsLock;
private final CyclicBarrier eatingBarrier;
private final Dock dock;
private final HoboGroup group;
private final Logger logger;

public Hobo(HoboGroup group, Dock dock, CyclicBarrier eatingBarrier) {
this.dock = dock;
this.group = group;
this.eatingBarrier = eatingBarrier;
this.logger = createLogger();
}

private Logger createLogger() {
Logger logger = Logger.getLogger(Hobo.class.getName());
try {
// Создание обработчика файла логов
FileHandler fileHandler = new FileHandler("log/hobo.log");
fileHandler.setFormatter(new SimpleFormatter());
logger.addHandler(fileHandler);
} catch (Exception e) {
logger.log(Level.SEVERE, "Failed to create logger", e);
}
return logger;
}

public void becomeCook(Semaphore cookSemaphore, Lock ingredientsLock, Semaphore eatingSemaphore) {
isCook = true;
this.cookSemaphore = cookSemaphore;
this.ingredientsLock = ingredientsLock;
this.eatingSemaphore = eatingSemaphore;
}

@Override
public void run() {
int stealingTime = ConfigReader.getInstance().getStealingTime();
try {
if (isCook) {
while (true) {
tryCook();
}
}
while (true) {
Thread.sleep(stealingTime * 1000L);
while (group.isEating().get()) {
eatingBarrier.await();
Thread.sleep(ConfigReader.getInstance().getEatingTime() * 1000L);
}
stealIngredient();
}
} catch (InterruptedException | BrokenBarrierException e) {
logger.log(Level.SEVERE, "Thread interrupted", e);
}
}

private void stealIngredient() {
int ingredient = dock.steal();
group.putIngredient(ingredient);
logger.info("Stole ingredient: " + ConfigReader.getInstance().getCargoTypes()[ingredient]);
}

private void tryCook() {
try {
cookSemaphore.acquire();
ingredientsLock.lock();
if (group.isEating().get()) {
ingredientsLock.unlock();
eatingBarrier.await();
Thread.sleep(ConfigReader.getInstance().getEatingTime() * 1000L);
return;
}
int[] ingredients = group.getIngredients();
int[] ingredientsCount = ConfigReader.getInstance().getIngredientsCount();
for (int i = 0; i < ingredients.length; i++) {
if (ingredients[i] < ingredientsCount[i]) {
ingredientsLock.unlock();
return;
}
}
eatingSemaphore.release();
group.isEating().set(true);
ingredientsLock.unlock();
eatingBarrier.await();
Thread.sleep(ConfigReader.getInstance().getEatingTime() * 1000L);
} catch (InterruptedException | BrokenBarrierException e) {
throw new RuntimeException(e);
}
}
}
Loading