Skip to content

Commit 4e4e0a5

Browse files
authored
Merge pull request #2 from Pyrokines17/lab4
lab4
2 parents 849f956 + 4d264bb commit 4e4e0a5

31 files changed

Lines changed: 1542 additions & 0 deletions

‎lab4/.gitignore‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
target/
2+
!.mvn/wrapper/maven-wrapper.jar
3+
!**/src/main/**/target/
4+
!**/src/test/**/target/
5+
6+
### IntelliJ IDEA ###
7+
.idea/modules.xml
8+
.idea/jarRepositories.xml
9+
.idea/compiler.xml
10+
.idea/libraries/
11+
*.iws
12+
*.iml
13+
*.ipr
14+
15+
### Eclipse ###
16+
.apt_generated
17+
.classpath
18+
.factorypath
19+
.project
20+
.settings
21+
.springBeans
22+
.sts4-cache
23+
24+
### NetBeans ###
25+
/nbproject/private/
26+
/nbbuild/
27+
/dist/
28+
/nbdist/
29+
/.nb-gradle/
30+
build/
31+
!**/src/main/**/build/
32+
!**/src/test/**/build/
33+
34+
### VS Code ###
35+
.vscode/
36+
37+
### Mac OS ###
38+
.DS_Store

‎lab4/conf.txt‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
BODY_SIZE=100
2+
MOTOR_SIZE=150
3+
ACCESSORY_SIZE=200
4+
AUTO_SIZE=250
5+
SUPPLIERS=3
6+
WORKERS=4
7+
DEALERS=5
8+
LOGS=1

‎lab4/factory.png‎

124 KB
Loading

‎lab4/pom.xml‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>ru.nsu.gunko</groupId>
8+
<artifactId>lab4</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
11+
<properties>
12+
<maven.compiler.source>21</maven.compiler.source>
13+
<maven.compiler.target>21</maven.compiler.target>
14+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
15+
</properties>
16+
17+
</project>

‎lab4/readme.md‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
2+
# Задача 4. Эмулятор работы фабрики (многопоточное программирование)
3+
4+
Напишите приложение, эмулирующее работу фабрики по сборке автомашин. Машина состоит из 3-х частей: кузов, двигатель и аксессуары. Машину надо собрать и отвезти на склад, откуда она поступает дилерам. Процесс работы фабрики показан на картинке:
5+
6+
![Schema](./factory.png)
7+
8+
**Технические условия:**
9+
10+
1. Все склады имеют определенный размер, который нельзя превышать. Размеры складов, количество сборщиков, поставщиков и дилеров задаются в конфигурационном файле.
11+
2. Приложение предоставляет графический интерфейс, где можно смотреть основные параметры работы фабрики и контролировать процесс.
12+
3. Каждый сборщик, поставщик и дилер должен работать в отдельном потоке.
13+
4. Для синхронизации и ожидания событий можно использовать мониторы синхронизации (`synchronized/notifyAll/wait`) либо средства из пакета `java.util.concurrent`. Синхронизация "на слипах" (`Thread.sleep`) или холостых циклах (`busy waiting`) не принимается.
14+
5. Каждая деталь - это отдельный объект с уникальным идентификатором. Хранить просто количество изделий/деталей нельзя.
15+
6. Каждый поставщик поставляет одну деталь раз в N миллисекунд. Если какой-то склад деталей полон, то поставщик ожидает освобождения места для деталей. Скорость работы поставщиков определяется 3-мя ползунками (для каждого типа деталей). Должно отображаться кол-во деталей на каждом из складов в текущий момент и кол-во деталей, произведенных поставщиками (для поставщиков аксессуаров можно общий показывать).
16+
7. Каждый дилер запрашивают со склада готовой продукции 1 машину в M миллисекунд. Скорость запрашивания машин можно регулировать ползунком в интерфейсе окна. Интерфейс также должен показывать кол-во произведенных машин (вообще) и кол-во машин на складе в данный момент. При отправке машины дилеру информация о покупке должна писаться в лог работы фабрики (в файл или `System.out`) в виде строки: `<Time>: Dealer <Number>: Auto <ID> (Body: <ID>, Motor: <ID>, Accessory: <ID>)`.
17+
8. Контроллер склада готовой продукции просыпается при любой отправке машины со склада продукции. Он анализирует состояние склада и передает запрос на изготовление новых машин (в случае необходимости) на фабрику.
18+
9. Управлением потоками занимается один или несколько пулов потоков (thread pool). Можно воспользоваться стандартными (см. `java.util.concurrent.Executors`).
19+
10. Задачами для пула потоков являются запросы на создание новых машин (от контроллера склада готовых изделий). При выполнении такой задачи сборщик должен взять по одной детали, необходимой для сборки машины, с соответствующих складов. Если на складе нет нужной детали, то поток ждет поставки. Собирая новую машину, рабочий создает новый объект с помощью всех необходимых объектов, представляющих детали. После этого объект отправляется на склад готовой продукции. Если склад полон, то рабочий ждет освобождения места для новой машины. Интерфейс должен отображать, сколько всего было сделано машин и сколько задач еще ждут исполнителя (в очереди задач).
20+
11. **Код организован согласно MVC, классы объектной модели (деталь, склад, поставщик, сборщик и т.д.) не должны зависеть от библиотеки графического интерфейса.**
21+
12. Конфигурационный файл должен предоставлять настройки для задания вместимости всех складов и количестве всех типов потоков. Примерный список параметров в конфигурационном файле (просьба использовать свои имена):
22+
23+
```plain
24+
StorageBodySize=100
25+
StorageMotorSize=100
26+
StorageAccessorySize=100
27+
StorageAutoSize=100
28+
AccessorySuppliers=5
29+
Workers=10
30+
Dealers=20
31+
LogSale=true
32+
```
33+
13. Программа должна корректно завершаться. При получении сигнала о закрытии окна все потоки должны корректно прерываться, и лог-файл закрываться.
34+
35+
## Дополнительно
36+
37+
На оценку "4" и выше - собственная реализация пула потоков (интерфейс - на ваше усмотрение). Он должен быть реализован в отдельном пакете и не зависеть от остальной системы. Должна быть возможность корректного закрытия пула с завершением всех потоков. Самостоятельно определите стратегию, когда ваш пул создает новые потоки и когда завершает старые, но должны выполняться следующие условия:
38+
1. Нельзя для каждой задачи создавать новый поток, потоки должны переиспользоваться.
39+
2. Максимальное число потоков под управлением пула в любой момент времени - фиксировано (задается в конструкторе).
40+
3. Потоки должны создаваться и закрываться динамически во время работы пула в зависимости от каких-то условий. Нельзя один раз создать N потоков и потом их использовать.
41+
42+
На оценку "5" - условия выше, плюс ваш пул потоков должен полностью реализовывать интерфейс `java.util.concurrent.ExecutorService`. Также он должен в конструкторе принимать `BlockingQueue<Runnable>`, которая будет использоваться для хранения задач - таким образом поведение вашего пула можно будет дополнительно параметризовать, передав специфическую реализацию очереди задач.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package ru.nsu.gunko;
2+
3+
import ru.nsu.gunko.view.*;
4+
import ru.nsu.gunko.model.*;
5+
import ru.nsu.gunko.model.base.*;
6+
7+
import java.util.*;
8+
9+
public class Main {
10+
public static void main(String[] args) {
11+
if (args.length == 0) {
12+
System.err.println("Need conf...");
13+
System.exit(1);
14+
}
15+
16+
Preparer preparer = new Preparer();
17+
18+
Map<String, Integer> map = preparer.readLine(args[0]);
19+
Storages storages = preparer.createStorages(map);
20+
21+
Model model = new Model(map, storages);
22+
Window window = new Window(model);
23+
model.setModelListener(window);
24+
25+
model.start(map, storages);
26+
model.getController().signal();
27+
28+
while (window.getFlag()) {
29+
try {
30+
synchronized (model) {
31+
model.wait();
32+
}
33+
} catch (InterruptedException e) {
34+
throw new RuntimeException(e);
35+
}
36+
}
37+
38+
preparer.end(model);
39+
window.setVisible(false);
40+
window.dispose();
41+
}
42+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package ru.nsu.gunko.controller;
2+
3+
import ru.nsu.gunko.model.base.*;
4+
5+
import javax.swing.*;
6+
import javax.swing.event.*;
7+
import java.util.List;
8+
9+
public class SwingController implements ChangeListener {
10+
private final JSlider slider;
11+
private final Model model;
12+
private final List<JLabel> labels;
13+
14+
private final int id;
15+
private boolean flag;
16+
17+
public SwingController(Model model, int id, JSlider slider, List<JLabel> labels) {
18+
this.model = model;
19+
this.id = id;
20+
this.slider = slider;
21+
this.flag = true;
22+
this.labels = labels;
23+
}
24+
25+
@Override
26+
public void stateChanged(ChangeEvent changeEvent) {
27+
double SPEED = 200;
28+
double bufValue = 10000;
29+
double value = SPEED*slider.getValue()/100;
30+
31+
if (flag && value!=0) {
32+
switch (id) {
33+
case 0: {
34+
model.getDealers().getSell().setTime(bufValue / value);
35+
labels.get(id).setText("Speed: "+slider.getValue()+"%");
36+
break;
37+
}
38+
case 1: {
39+
model.getSuppliers().getPuts().bodyPut().setTime(bufValue / value);
40+
labels.get(id).setText("Speed: "+slider.getValue()+"%");
41+
break;
42+
}
43+
case 2: {
44+
model.getSuppliers().getPuts().motorPut().setTime(bufValue / value);
45+
labels.get(id).setText("Speed: "+slider.getValue()+"%");
46+
break;
47+
}
48+
case 3: {
49+
model.getSuppliers().getPuts().accessoryPut().setTime(bufValue / value);
50+
labels.get(id).setText("Speed: "+slider.getValue()+"%");
51+
break;
52+
}
53+
}
54+
}
55+
}
56+
57+
public void setFlag(boolean flag) {
58+
this.flag = flag;
59+
}
60+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package ru.nsu.gunko.model;
2+
3+
public enum Config {
4+
BODY_SIZE,
5+
MOTOR_SIZE,
6+
ACCESSORY_SIZE,
7+
AUTO_SIZE,
8+
SUPPLIERS,
9+
WORKERS,
10+
DEALERS,
11+
LOGS
12+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package ru.nsu.gunko.model;
2+
3+
import ru.nsu.gunko.model.car.*;
4+
import ru.nsu.gunko.model.base.*;
5+
import ru.nsu.gunko.model.parts.body.*;
6+
import ru.nsu.gunko.model.parts.motor.*;
7+
import ru.nsu.gunko.model.parts.accessory.*;
8+
9+
import java.io.*;
10+
import java.util.*;
11+
import java.util.concurrent.*;
12+
13+
public class Preparer {
14+
public Storages createStorages(Map<String, Integer> map) {
15+
BlockingQueue<Body> bodyStorage = new ArrayBlockingQueue<>(map.get(Config.BODY_SIZE.name()));
16+
BlockingQueue<Motor> motorStorage = new ArrayBlockingQueue<>(map.get(Config.MOTOR_SIZE.name()));
17+
BlockingQueue<Accessory> accessoryStorage = new ArrayBlockingQueue<>(map.get(Config.ACCESSORY_SIZE.name()));
18+
BlockingQueue<Car> carStorage = new ArrayBlockingQueue<>(map.get(Config.AUTO_SIZE.name()));
19+
20+
return new Storages(bodyStorage, motorStorage, accessoryStorage, carStorage);
21+
}
22+
23+
public Map<String, Integer> readLine(String name) {
24+
Map<String, Integer> map = new HashMap<>();
25+
String[] parts;
26+
String line;
27+
28+
try (BufferedReader fileReader = new BufferedReader(new FileReader(name))) {
29+
while ((line = fileReader.readLine()) != null) {
30+
parts = line.split("=");
31+
map.put(parts[0], Integer.parseInt(parts[1]));
32+
}
33+
} catch (IOException e) {
34+
throw new RuntimeException(e);
35+
}
36+
37+
return map;
38+
}
39+
40+
public void end(Model model) {
41+
model.getSuppliers().finish();
42+
model.getFactory().finish();
43+
model.getController().finish();
44+
model.getDealers().finish();
45+
}
46+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package ru.nsu.gunko.model;
2+
3+
import ru.nsu.gunko.model.car.*;
4+
import ru.nsu.gunko.model.parts.body.*;
5+
import ru.nsu.gunko.model.parts.motor.*;
6+
import ru.nsu.gunko.model.parts.accessory.*;
7+
8+
import java.util.concurrent.*;
9+
10+
public record Storages(BlockingQueue<Body> bodyStorage, BlockingQueue<Motor> motorStorage,
11+
BlockingQueue<Accessory> accessoryStorage, BlockingQueue<Car> carStorage) {
12+
}

0 commit comments

Comments
 (0)