diff --git a/lab-02/DocksAndHobos/DocksAndHobos.iml b/lab-02/DocksAndHobos/DocksAndHobos.iml
new file mode 100644
index 0000000..bd0c28c
--- /dev/null
+++ b/lab-02/DocksAndHobos/DocksAndHobos.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lab-02/DocksAndHobos/config.json b/lab-02/DocksAndHobos/config.json
new file mode 100644
index 0000000..35e3f96
--- /dev/null
+++ b/lab-02/DocksAndHobos/config.json
@@ -0,0 +1,22 @@
+{
+ "generating_time": 15,
+ "ship_capacity_min": 20,
+ "ship_capacity_max": 100,
+ "max_ships": 4,
+ "unloading_speed": 7,
+ "dock_capacity": 100,
+ "hobos": 10,
+ "stealing_time": 2,
+ "eating_time": 3,
+ "cargo_types" : [
+ "meat",
+ "fish",
+ "oil"
+ ],
+
+ "ingredients_count" : [
+ 7,
+ 2,
+ 10
+ ]
+}
\ No newline at end of file
diff --git a/lab-02/DocksAndHobos/src/by/DaniilDomnin/doks_and_hobos/Controller.java b/lab-02/DocksAndHobos/src/by/DaniilDomnin/doks_and_hobos/Controller.java
new file mode 100644
index 0000000..bcfe8e5
--- /dev/null
+++ b/lab-02/DocksAndHobos/src/by/DaniilDomnin/doks_and_hobos/Controller.java
@@ -0,0 +1,63 @@
+package by.DaniilDomnin.doks_and_hobos;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class Controller {
+ Controller(ShipGenerator generator, Docks docks, long generating_time, long max_ships) throws InterruptedException {
+ this.generator = generator;
+ this.generating_time = generating_time;
+ this.max_ships = max_ships;
+ this.docks = docks;
+ ship_count = new AtomicInteger();
+ consoleLOgger = Logger.getLogger(" ");
+ Thread thread = new Thread(docks::StartStealing);
+ thread.start();
+ Generating();
+ }
+
+ private void Generating() throws InterruptedException {
+ while (true) {
+ if (ship_count.get() < max_ships) {
+ Ship ship = generator.GenerateShip();
+ consoleLOgger.log(Level.INFO, "Generate new ship");
+ Thread thread = new Thread(()->{
+ try {
+ Uploading(ship);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ thread.start();
+ ship_count.incrementAndGet();
+ } else {
+ consoleLOgger.log(Level.INFO, "The ship sank in the tunnel");
+ }
+
+ Thread.sleep(generating_time * 1000);
+ }
+ }
+
+ private void Uploading(Ship ship) throws InterruptedException {
+ docks.Unloading(ship);
+ ship_count.decrementAndGet();
+ }
+
+ public static Logger GetConsoleLogger () {
+ return consoleLOgger;
+ }
+
+ private final ShipGenerator generator;
+
+ private static Logger consoleLOgger;
+
+ private final AtomicInteger ship_count;
+ private final long generating_time;
+
+ private final long max_ships;
+
+ private final Docks docks;
+}
diff --git a/lab-02/DocksAndHobos/src/by/DaniilDomnin/doks_and_hobos/Docks.java b/lab-02/DocksAndHobos/src/by/DaniilDomnin/doks_and_hobos/Docks.java
new file mode 100644
index 0000000..550dbd9
--- /dev/null
+++ b/lab-02/DocksAndHobos/src/by/DaniilDomnin/doks_and_hobos/Docks.java
@@ -0,0 +1,125 @@
+package by.DaniilDomnin.doks_and_hobos;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Random;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.logging.Level;
+
+public class Docks {
+ Docks(long dock_capacity, long unloading_speed, ArrayList cargo_names, long hobos, ArrayList ingredients_count, long eating_time, long stealing_time) {
+ this.dock_capacity = dock_capacity;
+ this.unloading_speed = unloading_speed;
+ this.hobos = hobos;
+ this.ingredients_count = ingredients_count;
+ this.eating_time = eating_time;
+ this.stealing_time = stealing_time;
+ this.cargo_names = cargo_names;
+ current_ingredients_count = new ArrayList<>();
+ for (int i = 0; i < ingredients_count.size(); ++i) {
+ current_ingredients_count.add(0L);
+ }
+ add_ingredient_mutex = new ReentrantLock();
+ cargo_names.forEach(x -> {
+ cargo_count.put(x, 0L);
+ });
+
+ }
+
+ public void Unloading (Ship ship) throws InterruptedException {
+ long capacity = ship.GetCapacity();
+ while (ship.GetCapacity() != 0) {
+ Thread.sleep(1000);
+ cargo_count.put(ship.GetCargoName(), Math.min(cargo_count.get(ship.GetCargoName()) + Math.min(ship.GetCapacity(), unloading_speed), dock_capacity));
+ ship.SetCapacity(Math.max(0, ship.GetCapacity() - unloading_speed));
+ }
+ Controller.GetConsoleLogger().log(Level.INFO, "Unload " + capacity + " " + ship.GetCargoName());
+ }
+
+ public void StartStealing () {
+ for (int i = 0; i < hobos - 2; ++i) {
+ Thread thread = new Thread(() -> {
+ try {
+ Stealing();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ thread.start();
+ }
+ }
+
+ private void Stealing () throws InterruptedException {
+ while (true) {
+ Thread.sleep(stealing_time * 1000);
+ add_ingredient_mutex.lock();
+ int index = GetStealIndex();
+ if (index == -1) {
+ continue;
+ }
+ Controller.GetConsoleLogger().log(Level.INFO, "Hobo steals " + cargo_names.get(index));
+ cargo_count.put(cargo_names.get(index), cargo_count.get(cargo_names.get(index)) - 1);
+ current_ingredients_count.set(index, current_ingredients_count.get(index) + 1);
+ if (CanStartEating()) {
+ ClearCurrentIngredients();
+ Controller.GetConsoleLogger().log(Level.INFO, "Hobos start eating");
+ Thread.sleep(eating_time * 1000);
+ Controller.GetConsoleLogger().log(Level.INFO, "Hobos finish eating");
+ }
+ add_ingredient_mutex.unlock();
+ }
+ }
+
+ private int GetStealIndex () {
+ ArrayList indexes = new ArrayList();
+ for (int i = 0; i < cargo_names.size(); ++i) {
+ if (cargo_count.get(cargo_names.get(i)) > 0) {
+ indexes.add(i);
+ }
+ }
+ if (indexes.size() == 0) {
+ return -1;
+ }
+ return indexes.get(new Random().nextInt(0, indexes.size()));
+ }
+
+ private void ClearCurrentIngredients() {
+ for (int i = 0; i < current_ingredients_count.size(); ++i) {
+ current_ingredients_count.set(i, current_ingredients_count.get(i) - ingredients_count.get(i));
+ }
+ }
+
+ private boolean CanStartEating () {
+ for (int i = 0; i < current_ingredients_count.size(); ++i) {
+ if (current_ingredients_count.get(i) < ingredients_count.get(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+
+
+ private final long dock_capacity;
+ private final long unloading_speed;
+
+ private final long hobos;
+
+ private final long eating_time;
+
+ private final long stealing_time;
+
+ private final ArrayList current_ingredients_count;
+
+ private final Lock add_ingredient_mutex;
+
+ private final ArrayList ingredients_count;
+
+ private final ArrayList cargo_names;
+
+ private final ConcurrentHashMap cargo_count = new ConcurrentHashMap<>();
+}
diff --git a/lab-02/DocksAndHobos/src/by/DaniilDomnin/doks_and_hobos/Main.java b/lab-02/DocksAndHobos/src/by/DaniilDomnin/doks_and_hobos/Main.java
new file mode 100644
index 0000000..ababf7e
--- /dev/null
+++ b/lab-02/DocksAndHobos/src/by/DaniilDomnin/doks_and_hobos/Main.java
@@ -0,0 +1,24 @@
+package by.DaniilDomnin.doks_and_hobos;
+
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+public class Main {
+
+ public static void main(String[] args) throws IOException, ParseException, InterruptedException {
+ Object obj = new JSONParser().parse(new FileReader(args[0]));
+ JSONObject jo = (JSONObject) obj;
+ ShipGenerator generator = new ShipGenerator((long)jo.get("ship_capacity_max"), (long)jo.get("ship_capacity_min"), (ArrayList) jo.get("cargo_types"));
+ Docks docks = new Docks((long)jo.get("dock_capacity"), (long)jo.get("unloading_speed"), (ArrayList) jo.get("cargo_types"), (long)jo.get("hobos"), (ArrayList) jo.get("ingredients_count"), (long)jo.get("eating_time"), (long)jo.get("stealing_time"));
+ Controller c = new Controller(generator, docks, (long)jo.get("generating_time"), (long)jo.get("max_ships"));
+ }
+}
\ No newline at end of file
diff --git a/lab-02/DocksAndHobos/src/by/DaniilDomnin/doks_and_hobos/Ship.java b/lab-02/DocksAndHobos/src/by/DaniilDomnin/doks_and_hobos/Ship.java
new file mode 100644
index 0000000..5a8b31f
--- /dev/null
+++ b/lab-02/DocksAndHobos/src/by/DaniilDomnin/doks_and_hobos/Ship.java
@@ -0,0 +1,23 @@
+package by.DaniilDomnin.doks_and_hobos;
+
+public class Ship {
+ Ship(long capacity, String cargo_name) {
+ this.capacity = capacity;
+ this.cargo_name= cargo_name;
+ }
+
+ public String GetCargoName () {
+ return cargo_name;
+ }
+
+ public long GetCapacity () {
+ return capacity;
+ }
+
+ public void SetCapacity (long capacity) {
+ this.capacity = capacity;
+ }
+
+ private long capacity;
+ private final String cargo_name;
+}
diff --git a/lab-02/DocksAndHobos/src/by/DaniilDomnin/doks_and_hobos/ShipGenerator.java b/lab-02/DocksAndHobos/src/by/DaniilDomnin/doks_and_hobos/ShipGenerator.java
new file mode 100644
index 0000000..53af099
--- /dev/null
+++ b/lab-02/DocksAndHobos/src/by/DaniilDomnin/doks_and_hobos/ShipGenerator.java
@@ -0,0 +1,23 @@
+package by.DaniilDomnin.doks_and_hobos;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+public class ShipGenerator {
+
+ ShipGenerator(long ship_capacity_max, long ship_capacity_min, ArrayList cargo_names) {
+ this.ship_capacity_max = ship_capacity_max;
+ this.ship_capacity_min = ship_capacity_min;
+ this.cargo_names = cargo_names;
+ }
+
+ public Ship GenerateShip() {
+ Random ran = new Random();
+ return new Ship(ran.nextLong(ship_capacity_min, ship_capacity_max + 1), cargo_names.get(ran.nextInt(0, cargo_names.size())));
+ }
+
+ private long ship_capacity_max;
+ private long ship_capacity_min;
+
+ private ArrayList cargo_names;
+}
diff --git a/lab-02/README.md b/lab-02/README.md
deleted file mode 100644
index 1d490cf..0000000
--- a/lab-02/README.md
+++ /dev/null
@@ -1,43 +0,0 @@
-# Docks & Hobos
-В данной задачем вам предстоит поработать с потоками и примитивами синхронизации в Java.
-
-# Архитектура приложения
-В задаче никого шаблона предложенно не будет, архитектура приложения полностью зависит только от вас (архитектура и чистота также будут оцениваться).
-
-Все переменные должны задаваться в файле *config.json*. Путь до этого файла передается аргументов в вашу программу, при запуске она читаетс все переменные из этого файла и конструирует необходимые сущности.
-
->Всю работу ведите в пакете `by.<ваш ник>.docks_and_hobos`
-
-# Основные действующие лица
-- *Генератор кораблей* — Генератор кораблей каждые _generating_time_ секунд производит подходящий к бухте грузовой корабль.
-- *Корабль* — Корабль может иметь разную грузоподъемность и один из типов груза. Диапазон грузоподъемноти коробля от _ship_capacity_min_ до _ship_capacity_max_, все типы грузов перечислены в массиве _cargo_types_.
-- *Тонель* — Заходя в бухту, корабли попадают в узкий тоннель, вмещающий только _max_ships_ кораблей. Корабли, которые не могут пройти, тонут. Корабли, находящиеся в тоннеле, ожидают вызова от доков.
-- *Доки* — Корабли швартуются в доках для разгрузки, которая идет со скоростью _unloading_speed_ единиц товара в секунду. Разгруженные товары хранятся в доках, максимальное количество хранимого товара _dock_capacity_ для каждой еденицы, если товар не помещается на склад его выкидывают.
-- *Бродяги* — В доках обитает _hobos > 2_ бродяг. Они вечно голодны и имеют тягу к высокой кухне, то есть питаются исключительно “Омерзительно длинными бутербродами”. В состав порции, достаточной для временного насыщения ватаги кулинаров входит по _X_i_ единиц _i-го_ ингридента, указывается в массиве _ingridients_count_. Бродяги воруют ингредиенты со складов в доках и готовят их над горящей бочкой: двое всегда занимаются готовкой, остальные воруют ингредиенты, при этом время, за которое один вор может украсть и принести единицу товара - _stealing_time_ секунд. Приготовив необходимую порцию еды, бродяги останавливаются на _eating_time_ секунд, чтобы поесть, после чего продолжают привычную рутину, при этом распределение ответственности за готовку и грабеж происходит случайным образом.
-
-# Полезные ссылки
-- С чего стоит начать - https://goo.gl/f1HZxk.
-- Атомарные переменные — https://www.baeldung.com/java-atomic-variables
-- Thread — https://www.simplilearn.com/tutorials/java-tutorial/thread-in-java
-- Рассказ про многопоточность с семинара — https://disk.yandex.ru/i/rPOOINFYFwGmHQ.
-- Рассказ про многопоточность в Java с семинара — https://disk.yandex.ru/i/m16sdlCFlhiJCw.
-
->Не испольузйте mutex и atomic там где это не требуется! Использование этих примитивов сильно замедляет выполнение программы.
-
-# ★ Логирование
-Добавьте в свое приложение библиотеку для логирования. Библиотека может быть произвольной. Логирование должно работать следющим образом:
-- Логируете все что вам кажется интересным.
-- Логирование должно производится и в консоль и в файл (тут может быть разный уровень логирования, чтобы не захлмалять консоль).
-- Каждый промежуток времени (выберите самостоятельно) файл с логами должен сохраняться и логи должны начать писаться в другой файл. Название файлов должно содержать начало записи логов в этот файл.
-- Сохраните любой лог (до 100 строчек) в репозитории.
-
-## Полезные ссылки
-- Обзор на разные библиотеки логирования — https://habr.com/ru/post/247647/
-- Настройка _log4j_ — https://www.codejava.net/coding/how-to-configure-log4j-as-logging-mechanism-in-java
-
-# ★★ Condition Variable
-Condition variable — явялется примитивом синхронизации и используется для построения более специфичных методов синхронизации таких как *Semaphore*, *Barier* и других.
-
-Разобраться что такое Condition Variable, как в общих чертах с помощью них построить *Semaphore* и *Barier*. Если необходимо добавить в свой код что-то из описанного выше.
-
-- Лекция в шаде — https://disk.yandex.ru/i/Lc9eYl-rO4Nunw