diff --git a/src/test/java/koz01/java2/lab07/ComplicatedProcess.java b/src/test/java/koz01/java2/lab07/ComplicatedProcess.java
new file mode 100644
index 0000000000000000000000000000000000000000..33ca54875015be9f6a76ac1c81e3b0ac04e08636
--- /dev/null
+++ b/src/test/java/koz01/java2/lab07/ComplicatedProcess.java
@@ -0,0 +1,51 @@
+package koz01.java2.lab07;
+
+import java.math.BigInteger;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
+public class ComplicatedProcess {
+
+	private Random rnd = new Random();
+
+	public void doNop(Consumer<Long> durationConsumer) {
+		long start = System.currentTimeMillis();
+		try {
+			TimeUnit.MILLISECONDS.sleep(rnd.nextInt(3001) + 2000);
+		}
+		catch (InterruptedException exc) {
+			log.error("sleep", exc);
+		}
+
+		durationConsumer.accept(System.currentTimeMillis() - start);
+	}
+
+	public Long doNopReturnDuration() {
+		long start = System.currentTimeMillis();
+		try {
+			TimeUnit.MILLISECONDS.sleep(rnd.nextInt(3001) + 2000);
+		}
+		catch (InterruptedException exc) {
+			log.error("sleep", exc);
+		}
+
+		return System.currentTimeMillis() - start;
+	}
+
+	public Long doFactorialReturnDuration() throws Exception {
+		long start = System.currentTimeMillis();
+		BigInteger bd = BigInteger.ONE;
+		if (start > 0) {
+			throw new RuntimeException("proof");
+		}
+		for (int i = 2; i < 50000; i++) {
+			bd = bd.multiply(BigInteger.valueOf(i));
+		}
+
+		return System.currentTimeMillis() - start;
+	}
+}
diff --git a/src/test/java/koz01/java2/lab07/TestThread.java b/src/test/java/koz01/java2/lab07/TestThread.java
new file mode 100644
index 0000000000000000000000000000000000000000..c186bb0ef2fbc80b32c37b81b9bd289f89a7acda
--- /dev/null
+++ b/src/test/java/koz01/java2/lab07/TestThread.java
@@ -0,0 +1,84 @@
+package koz01.java2.lab07;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.stream.Collectors;
+
+import org.junit.jupiter.api.Test;
+
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
+public class TestThread {
+
+	@Test
+	public void testThreads() {
+		final ComplicatedProcess cp = new ComplicatedProcess();
+		Collection<Thread> threads = new LinkedList<>();
+		Collection<Long> durations = new LinkedList<>();
+		long start = System.currentTimeMillis();
+		for (int i = 0; i < 10; i++) {
+			final int threadNu = i;
+			Thread t = new Thread() {
+				@Override
+				public void run() {
+					cp.doNop(l -> durations.add(l));
+				};
+			};
+			t.start();
+			threads.add(t);
+		}
+		threads.forEach(t -> {
+			try {
+				t.join();
+			}
+			catch (InterruptedException exc) {
+				log.error("join", exc);
+			}
+		});
+		long totalDuration = System.currentTimeMillis() - start;
+		long maxDuration = durations.stream().mapToLong(l -> l).max().getAsLong();
+		log.info("duration: {}/{} ms", maxDuration, totalDuration);
+	}
+
+	@Test
+	public void testExecutors() {
+		for (int i = 10; i <= 10; i++) {
+			ExecutorService executorService = Executors.newFixedThreadPool(i);
+			runExecutors(executorService, i);
+			executorService.shutdown();
+		}
+	}
+
+	private void runExecutors(ExecutorService executorService, int threads) {
+		final ComplicatedProcess cp = new ComplicatedProcess();
+		Collection<Future<Long>> futures = new LinkedList<>();
+
+		long start = System.currentTimeMillis();
+		for (int i = 0; i < 10; i++) {
+			Future<Long> future = executorService.submit(() -> cp
+				.doFactorialReturnDuration());
+			futures.add(future);
+		}
+
+		Collection<Long> durations = futures.stream().map(f -> {
+			try {
+				return f.get();
+			}
+			catch (InterruptedException | ExecutionException exc) {
+				log.error("error", exc.getCause());
+				return -1l;
+			}
+		}).collect(Collectors.toList());
+		long totalDuration = System.currentTimeMillis() - start;
+		long maxDuration = durations.stream().mapToLong(l -> l).max().getAsLong();
+		log.info("duration for #{} executors: {}/{} ms", threads, maxDuration,
+			totalDuration);
+	}
+
+}
+