Compare commits
6 Commits
7868add638
...
5365327d2f
| Author | SHA1 | Date | |
|---|---|---|---|
| 5365327d2f | |||
| 548619a0e5 | |||
| eb3fa2fbad | |||
| 9e5b33d600 | |||
| f26810f2f8 | |||
| 0f2f9532ef |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
target
|
target
|
||||||
|
tmp
|
||||||
@@ -7,9 +7,14 @@ public class App {
|
|||||||
Locale.setDefault(Locale.ENGLISH);
|
Locale.setDefault(Locale.ENGLISH);
|
||||||
|
|
||||||
Room room = new Room();
|
Room room = new Room();
|
||||||
Settings settings = new Settings(28, 0.4);
|
Thread roomThread = new Thread(room);
|
||||||
|
Settings settings = new Settings(room, 28, 0.4);
|
||||||
|
Thread settingsThread = new Thread(settings);
|
||||||
Controller controller = new Controller(room, settings);
|
Controller controller = new Controller(room, settings);
|
||||||
Thread controllerThread = new Thread(controller);
|
Thread controllerThread = new Thread(controller);
|
||||||
|
|
||||||
|
roomThread.start();
|
||||||
|
settingsThread.start();
|
||||||
controllerThread.start();
|
controllerThread.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ public class Fan implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Random random = new Random();
|
private Random random = new Random();
|
||||||
private double humidityMaxStep = 0.03;
|
private double humidityMaxStep = 0.005;
|
||||||
private long maxStepTimeMs = 3000;
|
private long maxStepTimeMs = 500;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ public class Heater implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Random random = new Random();
|
private Random random = new Random();
|
||||||
private double temperatureMaxStep = 1;
|
private double temperatureMaxStep = 0.25;
|
||||||
private long maxStepTimeMs = 3000;
|
private long maxStepTimeMs = 500;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|||||||
@@ -39,16 +39,18 @@ public class Room implements Runnable {
|
|||||||
|
|
||||||
// Параметры произвольного изменения температуры и влажности в комнате
|
// Параметры произвольного изменения температуры и влажности в комнате
|
||||||
private Random random = new Random();
|
private Random random = new Random();
|
||||||
private double temperatureMaxStep = 1;
|
private double temperatureMaxStep = 0.12; // примерно 0.5% от средних значений
|
||||||
private double humidityMaxStep = 0.05;
|
private double humidityMaxStep = 0.003;
|
||||||
private long maxStepTimeMs = 3000;
|
private long maxStepTimeMs = 500;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
// Пусть температура и влажность произвольно изменяются со временем
|
// Пусть температура и влажность почти произвольно изменяются со временем,
|
||||||
|
// но со временем становится немного холоднее (комната остывает), а влажность
|
||||||
|
// немного растёт (потому что нужно иногда проветривать).
|
||||||
while (!Thread.interrupted()) {
|
while (!Thread.interrupted()) {
|
||||||
temperature += (random.nextDouble() - 0.5) * 2 * temperatureMaxStep;
|
temperature += (random.nextDouble() - 0.6) * 2 * temperatureMaxStep;
|
||||||
humidity += (random.nextDouble() - 0.5) * 2 * humidityMaxStep;
|
humidity += (random.nextDouble() - 0.4) * 2 * humidityMaxStep;
|
||||||
|
|
||||||
Utils.sleepRandomTime((long) (maxStepTimeMs * 0.5), maxStepTimeMs);
|
Utils.sleepRandomTime((long) (maxStepTimeMs * 0.5), maxStepTimeMs);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import java.util.Random;
|
|||||||
* Симулирует переодическое изменение настроек пользователем.
|
* Симулирует переодическое изменение настроек пользователем.
|
||||||
*/
|
*/
|
||||||
public class Settings implements Runnable {
|
public class Settings implements Runnable {
|
||||||
|
private Room room;
|
||||||
|
|
||||||
private double temperature;
|
private double temperature;
|
||||||
|
|
||||||
public double getTemperature() {
|
public double getTemperature() {
|
||||||
@@ -18,24 +20,33 @@ public class Settings implements Runnable {
|
|||||||
return humidity;
|
return humidity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Settings(double temperature, double humidity) {
|
public Settings(Room room, double temperature, double humidity) {
|
||||||
|
this.room = room;
|
||||||
this.temperature = temperature;
|
this.temperature = temperature;
|
||||||
this.humidity = humidity;
|
this.humidity = humidity;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Параметры произвольного изменения настроек температуры и влажности в комнате
|
// Параметры произвольного изменения настроек температуры и влажности в комнате
|
||||||
private Random random = new Random();
|
private Random random = new Random();
|
||||||
private double temperatureMaxStep = 10;
|
private double temperatureMaxStep = 6;
|
||||||
private double humidityMaxStep = 0.15;
|
private double humidityMaxStep = 0.10;
|
||||||
private long maxStepTimeMs = 20000;
|
private long maxStepTimeMs = 30000;
|
||||||
|
|
||||||
|
private void log(String string) {
|
||||||
|
System.out.printf("[Settings in room %s] %s\n", room.name, string);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
while (!Thread.interrupted()) {
|
while (!Thread.interrupted()) {
|
||||||
|
Utils.sleepRandomTime((long) (maxStepTimeMs * 0.5), maxStepTimeMs);
|
||||||
|
|
||||||
temperature += (random.nextDouble() - 0.5) * 2 * temperatureMaxStep;
|
temperature += (random.nextDouble() - 0.5) * 2 * temperatureMaxStep;
|
||||||
humidity += (random.nextDouble() - 0.5) * 2 * humidityMaxStep;
|
humidity += (random.nextDouble() - 0.5) * 2 * humidityMaxStep;
|
||||||
|
|
||||||
Utils.sleepRandomTime((long) (maxStepTimeMs * 0.5), maxStepTimeMs);
|
log(String.format(
|
||||||
|
"Changed to temperature %.2fC°, humidity %.2f%%",
|
||||||
|
temperature, humidity));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,76 @@ package ru.spbstu.telematics.java;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
class SampleTests {
|
import java.lang.management.ManagementFactory;
|
||||||
|
import java.lang.management.ThreadMXBean;
|
||||||
|
|
||||||
|
public class AppTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тест проверяет, что при параллельном запуске всех потоков
|
||||||
|
* не возникает взаимной блокировки (deadlock).
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
void sampleTest() {
|
void testNoDeadlock() throws InterruptedException {
|
||||||
assertTrue(true);
|
Room room = new Room();
|
||||||
|
Settings settings = new Settings(room, 28.0, 0.4);
|
||||||
|
Controller controller = new Controller(room, settings);
|
||||||
|
Thread controllerThread = new Thread(controller);
|
||||||
|
Thread roomThread = new Thread(room);
|
||||||
|
|
||||||
|
controllerThread.start();
|
||||||
|
roomThread.start();
|
||||||
|
|
||||||
|
// Будем проверять наличие deadlock несколько раз с периодом 1 сек
|
||||||
|
// Общая длительность теста 10 секунд
|
||||||
|
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
long[] threadIds = threadBean.findDeadlockedThreads();
|
||||||
|
// Если возвращается не null, значит обнаружен deadlock
|
||||||
|
assertNull(threadIds, "Обнаружен deadlock.");
|
||||||
|
}
|
||||||
|
|
||||||
|
controllerThread.interrupt();
|
||||||
|
roomThread.interrupt();
|
||||||
|
|
||||||
|
controllerThread.join();
|
||||||
|
roomThread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Тест проверяет отсутствие гонок (race conditions),
|
||||||
|
* когда значения становятся очевидно некорректными или программа "падает".
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void testNoRaceCondition() throws InterruptedException {
|
||||||
|
Room room = new Room();
|
||||||
|
Settings settings = new Settings(room, 25.0, 0.4);
|
||||||
|
Controller controller = new Controller(room, settings);
|
||||||
|
Thread controllerThread = new Thread(controller, "Controller-Thread");
|
||||||
|
Thread roomThread = new Thread(room, "Room-Thread");
|
||||||
|
|
||||||
|
controllerThread.start();
|
||||||
|
roomThread.start();
|
||||||
|
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
long testDuration = 10000;
|
||||||
|
|
||||||
|
while (System.currentTimeMillis() - startTime < testDuration) {
|
||||||
|
double t = room.getTemperature();
|
||||||
|
double h = room.getHumidity();
|
||||||
|
|
||||||
|
assertTrue(t > -50 && t < 100, "Температура вышла за пределы допустимых значений, возможна гонка");
|
||||||
|
assertTrue(h >= -0.5 && h <= 1.5, "Влажность вышла за пределы допустимых значений, возможна гонка");
|
||||||
|
|
||||||
|
Thread.sleep(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
controllerThread.interrupt();
|
||||||
|
roomThread.interrupt();
|
||||||
|
|
||||||
|
controllerThread.join();
|
||||||
|
roomThread.join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user