Compare commits

..

6 Commits

7 changed files with 106 additions and 20 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
target target
tmp

View File

@@ -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();
} }
} }

View File

@@ -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() {

View File

@@ -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() {

View File

@@ -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);
} }

View File

@@ -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));
} }
} }
} }

View File

@@ -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();
} }
} }