diff --git a/examples/README.md b/examples/README.md
index 77699970..47719ffe 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -4,9 +4,11 @@
* *unit-testing-plain-spring* - Spring
* *unit-testing-spring-boot* - , Spring Boot
+* *unit-testing-pure-spring-parallel* - " " "" IOService
+* *ioservice-replacing-example* - UI -> Swing UI, IOService
* *hibernate-fetch-mode-demo* - Hibernate, N+1
* *mongo-db-demo* - MongoDB, MongoEventListener, Mongock
* *docker-test-containers* - TestContainers
* *spring-cloud-demo-stvort* - Config server, Eureka, Zuul, Feign client
* *spring-mail-integration-demo* - SpringMail SpringIntegration
-* *liquibase-demo* - liquibase
\ No newline at end of file
+* *liquibase-demo* - liquibase
diff --git a/examples/ioservice-replacing-example/.gitignore b/examples/ioservice-replacing-example/.gitignore
new file mode 100644
index 00000000..c456c4a3
--- /dev/null
+++ b/examples/ioservice-replacing-example/.gitignore
@@ -0,0 +1,25 @@
+/target/
+!.mvn/wrapper/maven-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+/build/
diff --git a/examples/ioservice-replacing-example/README.md b/examples/ioservice-replacing-example/README.md
new file mode 100644
index 00000000..e624c807
--- /dev/null
+++ b/examples/ioservice-replacing-example/README.md
@@ -0,0 +1,7 @@
+## Пример подмены консольного UI -> Swing UI, с помощью смены реализации IOService
+
+* *В примере есть класс проводящий опрос PollService и использующий для этого IOService*
+* *В зависимости от настройки use.swing в application.yml создаются либо бины из пакета console, либо бины из пакета swing*
+* *Т.к. один из этих бинов это реализация IOService, то получается либо консольный, либо оконный интерфейс программы без семы кода класса PollService*
+* *Оконный интерфейс представлен классом PollMainForm, который взаимодействует с основной частью программы, через очереди в сервисе MessageSystem*
+* *Через них же (с помощью IOService) основная часть программы взаимодействует с оконным интерфейсом*
diff --git a/examples/ioservice-replacing-example/pom.xml b/examples/ioservice-replacing-example/pom.xml
new file mode 100644
index 00000000..e98fb711
--- /dev/null
+++ b/examples/ioservice-replacing-example/pom.xml
@@ -0,0 +1,82 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.2.1.RELEASE
+
+
+
+ ru.otus
+ ioservice-replacing-example
+ 0.0.1-SNAPSHOT
+ ioservice-replacing-example
+ IOService replacing example
+
+
+ 11
+ 11
+ 11
+
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ ${junit-jupiter.version}
+ test
+
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ ${junit-jupiter.version}
+ test
+
+
+
+ org.junit.jupiter
+ junit-jupiter-params
+ ${junit-jupiter.version}
+ test
+
+
+
+ org.mockito
+ mockito-junit-jupiter
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/IOServiceExampleSpringBootApplication.java b/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/IOServiceExampleSpringBootApplication.java
new file mode 100644
index 00000000..05a57288
--- /dev/null
+++ b/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/IOServiceExampleSpringBootApplication.java
@@ -0,0 +1,13 @@
+package ru.otus.ioservice.example;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+
+
+@SpringBootApplication
+public class IOServiceExampleSpringBootApplication {
+
+ public static void main(String[] args) {
+ new SpringApplicationBuilder(IOServiceExampleSpringBootApplication.class).headless(false).run(args);
+ }
+}
diff --git a/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/api/IOService.java b/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/api/IOService.java
new file mode 100644
index 00000000..18572cea
--- /dev/null
+++ b/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/api/IOService.java
@@ -0,0 +1,6 @@
+package ru.otus.ioservice.example.api;
+
+public interface IOService {
+ void out(String message);
+ String readString();
+}
diff --git a/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/console/ConsoleIOService.java b/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/console/ConsoleIOService.java
new file mode 100644
index 00000000..bdf68124
--- /dev/null
+++ b/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/console/ConsoleIOService.java
@@ -0,0 +1,31 @@
+package ru.otus.ioservice.example.console;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Service;
+import ru.otus.ioservice.example.api.IOService;
+
+import java.io.PrintStream;
+import java.util.Scanner;
+
+@ConditionalOnProperty(name = "use.swing", havingValue = "false")
+@Service
+public class ConsoleIOService implements IOService {
+ private final PrintStream out;
+ private final Scanner sc;
+
+
+ public ConsoleIOService() {
+ this.out = System.out;
+ this.sc = new Scanner(System.in);
+ }
+
+ @Override
+ public void out(String message) {
+ out.println(message);
+ }
+
+ @Override
+ public String readString() {
+ return sc.nextLine();
+ }
+}
diff --git a/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/console/UIConfig.java b/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/console/UIConfig.java
new file mode 100644
index 00000000..32c1f367
--- /dev/null
+++ b/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/console/UIConfig.java
@@ -0,0 +1,18 @@
+package ru.otus.ioservice.example.console;
+
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import ru.otus.ioservice.example.poll.PollService;
+
+@ConditionalOnProperty(name = "use.swing", havingValue = "false")
+@Configuration
+public class UIConfig {
+
+ @Bean
+ public CommandLineRunner starter (PollService pollService) {
+ return args -> pollService.poll();
+ }
+
+}
diff --git a/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/poll/PollService.java b/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/poll/PollService.java
new file mode 100644
index 00000000..35382eb0
--- /dev/null
+++ b/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/poll/PollService.java
@@ -0,0 +1,29 @@
+package ru.otus.ioservice.example.poll;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import ru.otus.ioservice.example.api.IOService;
+
+@RequiredArgsConstructor
+@Service
+public class PollService {
+
+ private final IOService ioService;
+
+ public void poll() {
+ System.out.println("Началось!");
+
+ ioService.out("Как вас зовут?");
+ String name = ioService.readString();
+ ioService.out(String.format("Приятно познакомиться: %s", name));
+ ioService.out("Как ваши дела? Если хорошо, введите \"OK\"");
+ String res = ioService.readString();
+ if (res.equalsIgnoreCase("OK")) {
+ ioService.out("Это радует");
+ } else {
+ ioService.out("Ничего, скоро все наладится!");
+ }
+ ioService.out(String.format("До свидания %s", name));
+ }
+
+}
diff --git a/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/swing/MessageSystem.java b/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/swing/MessageSystem.java
new file mode 100644
index 00000000..9152c1c4
--- /dev/null
+++ b/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/swing/MessageSystem.java
@@ -0,0 +1,38 @@
+package ru.otus.ioservice.example.swing;
+
+import lombok.Data;
+import lombok.SneakyThrows;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.LinkedBlockingQueue;
+
+@Service
+public class MessageSystem {
+ private final LinkedBlockingQueue pollQueue;
+ private final LinkedBlockingQueue uiQueue;
+
+ public MessageSystem() {
+ pollQueue = new LinkedBlockingQueue<>();
+ uiQueue = new LinkedBlockingQueue<>();
+ }
+
+ @SneakyThrows
+ public void putToPollQueue(String message) {
+ pollQueue.put(message);
+ }
+
+ @SneakyThrows
+ public void putToUiQueue(String message) {
+ uiQueue.put(message);
+ }
+
+ @SneakyThrows
+ public String takeFromPollQueue() {
+ return pollQueue.take();
+ }
+
+ @SneakyThrows
+ public String takeFromUiQueue() {
+ return uiQueue.take();
+ }
+}
diff --git a/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/swing/PollMainForm.java b/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/swing/PollMainForm.java
new file mode 100644
index 00000000..521797f0
--- /dev/null
+++ b/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/swing/PollMainForm.java
@@ -0,0 +1,86 @@
+package ru.otus.ioservice.example.swing;
+
+import lombok.RequiredArgsConstructor;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+@RequiredArgsConstructor
+public class PollMainForm extends JFrame {
+
+ private final JPanel contentPane;
+ private final JLabel inLabel;
+ private final JTextField outTextField;
+ private final JButton outBtn;
+
+ private final MessageSystem ms;
+ private final AtomicBoolean runFlag;
+ private final ExecutorService uiFlow;
+
+ public PollMainForm(MessageSystem ms) throws HeadlessException {
+ super("Poll");
+ this.ms = ms;
+
+ runFlag = new AtomicBoolean(true);
+ uiFlow = Executors.newSingleThreadExecutor();
+
+ GridLayout layout = new GridLayout(3, 1);
+ contentPane = new JPanel(layout);
+ setContentPane(contentPane);
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+ inLabel = new JLabel("");
+ contentPane.add(inLabel);
+
+ outTextField = new JTextField(15);
+ contentPane.add(outTextField);
+
+ outBtn = new JButton("Ответить");
+ outBtn.addActionListener(e -> ms.putToPollQueue(outTextField.getText()));
+ contentPane.add(outBtn);
+ setOnCloseHandler();
+ setSize(450, 100);
+ }
+
+ void init() {
+ setLocationRelativeTo(null);
+ setVisible(true);
+ startUiFlow();
+ }
+
+ private void startUiFlow() {
+ uiFlow.execute(() -> {
+ while (runFlag.get()) {
+ try {
+ String msg = ms.takeFromUiQueue();
+ synchronized (inLabel) {
+ inLabel.setText(msg);
+ }
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ return;
+ }
+ }
+
+ });
+ }
+
+ private void setOnCloseHandler() {
+ addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ runFlag.set(false);
+ ms.putToUiQueue("exit");
+ uiFlow.shutdown();
+ e.getWindow().dispose();
+ }
+ });
+ }
+
+
+}
diff --git a/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/swing/SwingIOService.java b/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/swing/SwingIOService.java
new file mode 100644
index 00000000..324f8b97
--- /dev/null
+++ b/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/swing/SwingIOService.java
@@ -0,0 +1,26 @@
+package ru.otus.ioservice.example.swing;
+
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Service;
+import ru.otus.ioservice.example.api.IOService;
+
+@ConditionalOnProperty(name = "use.swing", havingValue = "true")
+@RequiredArgsConstructor
+@Service
+public class SwingIOService implements IOService {
+ private final MessageSystem ms;
+
+ @SneakyThrows
+ @Override
+ public void out(String message) {
+ ms.putToUiQueue(message);
+ }
+
+ @SneakyThrows
+ @Override
+ public String readString() {
+ return ms.takeFromPollQueue();
+ }
+}
diff --git a/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/swing/UIConfig.java b/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/swing/UIConfig.java
new file mode 100644
index 00000000..5eaf2d78
--- /dev/null
+++ b/examples/ioservice-replacing-example/src/main/java/ru/otus/ioservice/example/swing/UIConfig.java
@@ -0,0 +1,30 @@
+package ru.otus.ioservice.example.swing;
+
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import ru.otus.ioservice.example.poll.PollService;
+
+import java.awt.*;
+
+@ConditionalOnProperty(name = "use.swing", havingValue = "true")
+@Configuration
+public class UIConfig {
+
+ @Bean
+ public CommandLineRunner starter(PollService pollService, MessageSystem ms) {
+ return args -> {
+ EventQueue.invokeLater(() -> {
+ try {
+ PollMainForm mainForm = new PollMainForm(ms);
+ mainForm.init();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ });
+ pollService.poll();
+ };
+ }
+
+}
diff --git a/examples/ioservice-replacing-example/src/main/resources/application.yml b/examples/ioservice-replacing-example/src/main/resources/application.yml
new file mode 100644
index 00000000..efc3321a
--- /dev/null
+++ b/examples/ioservice-replacing-example/src/main/resources/application.yml
@@ -0,0 +1 @@
+use.swing: false
\ No newline at end of file
diff --git a/examples/unit-testing-pure-spring-parallel/README.md b/examples/unit-testing-pure-spring-parallel/README.md
new file mode 100644
index 00000000..ac7fe2b4
--- /dev/null
+++ b/examples/unit-testing-pure-spring-parallel/README.md
@@ -0,0 +1,7 @@
+## Пример "не удачного" и "работающего" варианта тестирования IOService в нескольких потоках
+
+В примере демонстрируется:
+* *возможность выполнения тестов в нескольких потоках (включается в junit-platform.properties\junit.jupiter.execution.parallel.enabled)*
+* *частый подход к тестированию сервиса консольного ввода/вывода, через подмену System.in/out (ClosedIOServiceTest)*
+* *проблемы возникающие при включении многопоточного режима исполнения тестов*
+* *вариант решения проблем с многопоточным исполнением тестов, через получение потоков ввода/вывода в конструкторе сервиса (OpenedIOServiceTest)*