├── .gitignore
├── README.md
├── ReleaseNotes.md
├── pom.xml
└── src
└── main
└── java
└── ru
└── javaops
└── masterjava
├── Main.java
├── matrix
├── MainMatrix.java
└── MatrixUtil.java
└── service
└── MailService.java
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | out
3 | target
4 | *.iml
5 | log
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Многомодульный maven. Многопоточность. XML. Веб сервисы. Удаленное взаимодействие
2 | ## Регистрация
3 | ## [Программа проекта](#Программа-проекта-1)
4 | ### [Изменения проекта (Release Notes)](ReleaseNotes.md)
5 |
6 | ### _Разработка полнофункционального многомодульного Maven проекта_
7 | #### состоящего из 3-х веб приложений:
8 |
9 | 
10 |
11 | - **приложение импорта** из XML (JAXB, StAX, XPath, XSLT)
12 | - **многопоточного почтового веб-сервиса** (JavaMail, java.util.concurrent, JAX-WS, MTOM, хендлеры авторизации, логирования и статистики)
13 | - **веб приложения отправки почты с вложениями**
14 | - по SOAP (JAX-WS, MTOM)
15 | - по JAX-RS (Jersey)
16 | - по JMS ([ActiveMQ](http://activemq.apache.org/))
17 | - через [AKKA](http://akka.io/)
18 | - используя асинхронные сервлеты 3.0
19 | - сохранение данных в PostgreSQL используя [jDBI](http://jdbi.org/)
20 | - миграция базы [LiquiBase](http://www.liquibase.org/)
21 | - использование в проекте [Guava](https://github.com/google/guava/wiki), [Thymleaf](http://www.thymeleaf.org/), [Lombok](https://projectlombok.org/), [StreamEx](https://github.com/amaembo/streamex),
22 | [Typesafe Config](https://github.com/typesafehub/config), [Java Microbenchmark JMH](http://openjdk.java.net/projects/code-tools/jmh)
23 |
24 | ### Требование к участникам
25 | Опыт программирования на Java. Базовые знания Maven.
26 |
27 | ### Необходимое ПО
28 | - JDK8
29 | - Git
30 | - IntelliJ IDEA
31 |
32 | # Первое занятие: многопоточность.
33 |
34 | ##  1. Вступление. Многопоточность и параллельность.
35 | 
36 |
37 | ##  2. Структура памяти Java. Ленивая инициализация.
38 | > В видео в `LazySingleton` ошибка: должно быть как в коде проекта `instance == null`
39 |
40 | ### Структура памяти: куча, стек, permanent/metaspace
41 | - JVM изнутри - оптимизация и профилирование.
42 | - Stack and Heap
43 | - Дополнительно:
44 | - Из каких частей состоит память java процесса.
45 | - Permanent область памяти
46 | > Замечание: [с JDK 7 String Pool переехал в Heap](https://topjava.ru/blog/rukovodstvo-po-string-pool-v-java)
47 | - [Стек и куча в Java](https://topjava.ru/blog/stack-and-heap-in-java)
48 | - Размер Java объектов
49 | - Оптимизация памяти
50 | - [Escape analysis и скаляризация: Пусть GC отдохнет](https://habr.com/company/jugru/blog/322348)
51 | - [Условия для размещения объекта в стеке](https://stackoverflow.com/a/43002529/548473)
52 |
53 | ### Ленивая инициализация
54 | - Реализация Singleton в JAVA
55 | - Double checked locking
56 | - Initialization-on-demand holder idiom
57 | - Подводные камни Singleton
58 |
59 | ##  3. Реализация многопоточности в Java
60 | - Параллелизм в Java
61 | - Монитор (синхронизация)
62 | - Compare-and-swap
63 | - Java Memory Model
64 | - Синхронизация потоков
65 | - Обзор java.util.concurrent.*
66 | - Как работает ConcurrentHashMap
67 | - Справочник по синхронизаторам java.util.concurrent.*
68 | - Использование ThreadLocal переменных
69 | - Николай Алименков — Прикладная многопоточность
70 | - Can thread switching happen in the synchronized block?
71 | - [The Deadlock Empire](https://deadlockempire.github.io/)
72 | - [Реактивное программирование - как, зачем и стоит ли?](https://habr.com/ru/company/oleg-bunin/blog/543386/)
73 |
74 | #### Tproger: Многопоточное программирование в Java 8
75 | - 1. Параллельное выполнение кода с помощью потоков
76 | - 2. Синхронизация доступа к изменяемым объектам
77 | - 3. Атомарные переменные и конкурентные таблицы
78 |
79 | ##  4. Реализация многопоточной отправки писем. Execution Framework
80 | > правка к видео: `22: completionService.submit(..)`
81 |
82 | Вычекать этот проект:
83 | ```git clone https://github.com/JavaOPs/masterjava.git```
84 |
85 | > - [Настройка git на свой репозиторий](https://github.com/JavaOPs/basejava/blob/master/lesson/lesson1.md#настройка-проекта)
86 | > - [Правила работы с патчами на проекте](https://github.com/JavaOPs/topjava/wiki/Git)
87 |
88 | #### Все изменения в проекте будут делаться на основе патчей: скачайте [1_1_MailService.patch](https://drive.google.com/file/d/0B9Ye2auQ_NsFTE5ZV3pzWElxTWM/view?resourcekey=0-TF7H5aadPlE3aQukNC5Ejg), положите его в проект, правой мышкой на нем сделайте Apply Patch ...
89 |
90 | ----------------------------
91 | - [Как сделать Java код проще и нагляднее](https://habrahabr.ru/company/wrike/blog/349652/)
92 |
93 | ### Ресурсы (основы)
94 | - Intuit, Потоки выполнения. Синхронизация
95 | - Алексей Владыкин, Основы многопоточность в Java
96 | - Виталий Чибриков, Java. Многопоточность
97 | - Computer Science Center, курс Параллельное программирование
98 | - Юрий Ткач, курс Advanced Java - Concurrency
99 | - Головач, курс Java Multithreading
100 | - [Перевод «Java Memory Model»](https://habr.com/ru/post/510454/)
101 |
102 | ---
103 | ##  Задание первого занятия
104 |
105 | - Применить оптимизацию к MatrixUtil.singleThreadMultiply
106 | - Реализовать метод `MatrixUtil.concurrentMultiply`, позволяющий многопоточно перемножать квадратные матрицы N*N.
107 | - Количество дочерних потоков ограничено `MainMatrix.THREAD_NUMBER`.
108 | - Добиться того, чтобы на матрице 1000*1000 многопоточная реализация была быстрее однопоточной
109 |
110 | -----
111 | ##  Подсказки по HW1
112 | - не делайте 1000 000 тасок, лучше их сделать крупнее
113 | - у меня разница между 4 и 1000 тасками по времени незаметна, поэтому делайте просто и не делайте сложно
114 | - наконец: можно не считать значение элемента результирующей матрицы C за раз, а накапливать (`concurrentMultiply3`). Мои результаты:
115 | ```
116 | Benchmark (matrixSize) Mode Cnt Score Error Units
117 | MatrixBenchmark.singleThreadMultiplyOpt 1000 ss 100 837,867 ± 25,530 ms/op
118 | MatrixBenchmark.concurrentMultiply2 1000 ss 100 394,294 ± 21,657 ms/op
119 | MatrixBenchmark.concurrentMultiply3 1000 ss 100 186,827 ± 11,882 ms/op
120 | ```
121 | -----
122 | # Программа проекта
123 |
124 | ## Занятие 2
125 | - Разбор ДЗ (многопоточная реализация умножения матриц)
126 | - Java Microbenchmark JMH (от Алексея Шипилева)
127 | - Формат XML. Создание схемы XSD.
128 | - Работа с XML в Java
129 | - JAXB, JAXP
130 | - StAX
131 | - XPath
132 | - XSLT
133 |
134 | ## Занятие 3
135 | - Разбор ДЗ (работа с XML)
136 | - [Обзор Guava](https://drive.google.com/open?id=0B9Ye2auQ_NsFeFB5a29JQ2tRNHM)
137 | - Монады. flatMap
138 | - SOA и Микросервисы
139 | - Многомодульный Maven проект
140 |
141 | ## Занятие 4
142 | - Разбор ДЗ (реализация структуры проекта, загрузка и разбор xml)
143 | - Thymleaf
144 | - Maven. Поиск и разрешение конфликтов зависимостей
145 | - Подключаем логирование с общими настройкам
146 | - Библиотеки и фреймворки для работы с JDBC.
147 | - Модуль persistence
148 |
149 | ## Занятие 5
150 | - Разбор ДЗ
151 | - Сохранение в базу в batch-моде с обработкой конфликтов
152 | - Вставка в несколько потоков
153 | - Конфигурирование приложения (Typesafe config)
154 | - Lombok
155 |
156 | ## Занятие 6
157 | - Разбор ДЗ (доработка модели и модуля export)
158 | - Миграция DB
159 | - Веб-сервисы (REST/SOAP)
160 | - Java реализации SOAP
161 | - Имплементируем Mail Service
162 |
163 | ## Занятие 7
164 | - Разбор ДЗ
165 | - реализация MailSender
166 | - сохранение результатов отправки в DB
167 | - импорт Проектов и Групп
168 | - Стили WSDL. Кастомизация WSDL
169 | - Публикация кастомизированного WSDL. Автогенерация.
170 | - Деплой в Tomcat
171 | - Создание клиента почтового сервиса
172 | - Реализация массовой и групповой отправки почты. HW7
173 |
174 | ## Занятие 8
175 | - Разбор ДЗ
176 | - Делаем общий mailService.wsdl
177 | - Обновление WSDL
178 | - Отправка почты из модуля webapp
179 | - Доступ к переменным maven в приложении
180 | - SOAP Exception. Выделение общей части схемы
181 | - Коррекция схемы
182 |
183 | ## Занятие 9
184 | - Добавление мавен плагинов (copy-rename-maven-plugin, maven-antrun-plugin, liquibase-maven-plugin)
185 | - Разбор ДЗ
186 | - Реализация вложений в веб-сервисе
187 | - Подключение MTOM
188 | - Реализация загрузки вложений в модуле webapp
189 | - Реализация вложений в почте
190 | - JAX-WS Message Context. Авторизация
191 | - JAX-WS Handlers (логирование SOAP)
192 | - Домашнее задание. Статистика
193 |
194 | ## Занятие 10
195 | - Разбор ДЗ
196 | - Реализация SOAP handlers
197 | - Конфигурирование сервисов
198 | - JavaEE
199 | - JAX-RS. Интеграция с Jersey
200 | - JMS. Интеграция с [ActiveMQ](http://activemq.apache.org/)
201 |
202 | ## Занятие 11
203 | - Авторизация в контейнере Tomcat
204 | - Отправка почты с вложениями
205 | - по JAX-RS
206 | - по JMS
207 | - Рефакторинг. Эксепшены в лямбдах Java 8
208 | - Concurrent and distributed applications toolkit AKKA
209 | - Отсылка почты через AKKA Actors (Typed и Untyped Actors)
210 | - Асинхронные сервлеты 3.0
211 | - Домашнее задание
212 | - Разбор решения с асинхронными сервлетами
213 | - [Выбор языка программирования](https://drive.google.com/open?id=0B9Ye2auQ_NsFZUVNakNxeUtGeFE)
214 |
--------------------------------------------------------------------------------
/ReleaseNotes.md:
--------------------------------------------------------------------------------
1 | # MasterJava Release Notes
2 |
3 | ### Masterjava 2
4 | - Добавил в проект
5 | - [Миграция базы через liquiBase](http://www.liquibase.org/quickstart.html)
6 | - Реализация модели/DAO/JUnit
7 | - Миграция DB
8 | - Maven плагины copy-rename-maven-plugin, maven-antrun-plugin, liquibase-maven-plugin
9 | - Авторизация в контейнере Tomcat
10 | - Concurrent and distributed applications toolkit AKKA (отсылка почты через AKKA Actors)
11 | - Асинхронные сервлеты 3.0
12 | - [Выбор языка программирования](https://drive.google.com/file/d/0B9Ye2auQ_NsFZUVNakNxeUtGeFE)
13 |
14 | - Pефакторинг
15 | - Реализация модуля export: Thymeleaf и Upload
16 | - Закэшировал `TemplateEngine`
17 | - Загрузка файлов через API Servlet 3.0
18 | - Сохранение в базу в batch-моде с обработкой конфликтов
19 | - При обновлении пользователей теперь используем `INSERT ON CONFLICT`
20 | - Работа со StAX (новый метод `startElement`)
21 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | ru.javaops
6 | masterjava
7 | jar
8 |
9 | 1.0-SNAPSHOT
10 |
11 | Master Java
12 | https://github.com/JavaOPs/masterjava
13 |
14 |
15 | 1.8
16 | UTF-8
17 | UTF-8
18 |
19 |
20 |
21 | masterjava
22 | install
23 |
24 |
25 | org.apache.maven.plugins
26 | maven-compiler-plugin
27 | 3.1
28 |
29 | ${java.version}
30 | ${java.version}
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/main/java/ru/javaops/masterjava/Main.java:
--------------------------------------------------------------------------------
1 | package ru.javaops.masterjava;
2 |
3 | /**
4 | * User: gkislin
5 | * Date: 05.08.2015
6 | *
7 | * @link http://caloriesmng.herokuapp.com/
8 | * @link https://github.com/JavaOPs/topjava
9 | */
10 | public class Main {
11 | public static void main(String[] args) {
12 | System.out.format("Hello MasterJava!");
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/ru/javaops/masterjava/matrix/MainMatrix.java:
--------------------------------------------------------------------------------
1 | package ru.javaops.masterjava.matrix;
2 |
3 | import java.util.concurrent.ExecutionException;
4 | import java.util.concurrent.ExecutorService;
5 | import java.util.concurrent.Executors;
6 |
7 | /**
8 | * gkislin
9 | * 03.07.2016
10 | */
11 | public class MainMatrix {
12 | private static final int MATRIX_SIZE = 1000;
13 | private static final int THREAD_NUMBER = 10;
14 |
15 | private final static ExecutorService executor = Executors.newFixedThreadPool(MainMatrix.THREAD_NUMBER);
16 |
17 | public static void main(String[] args) throws ExecutionException, InterruptedException {
18 | final int[][] matrixA = MatrixUtil.create(MATRIX_SIZE);
19 | final int[][] matrixB = MatrixUtil.create(MATRIX_SIZE);
20 |
21 | double singleThreadSum = 0.;
22 | double concurrentThreadSum = 0.;
23 | int count = 1;
24 | while (count < 6) {
25 | System.out.println("Pass " + count);
26 | long start = System.currentTimeMillis();
27 | final int[][] matrixC = MatrixUtil.singleThreadMultiply(matrixA, matrixB);
28 | double duration = (System.currentTimeMillis() - start) / 1000.;
29 | out("Single thread time, sec: %.3f", duration);
30 | singleThreadSum += duration;
31 |
32 | start = System.currentTimeMillis();
33 | final int[][] concurrentMatrixC = MatrixUtil.concurrentMultiply(matrixA, matrixB, executor);
34 | duration = (System.currentTimeMillis() - start) / 1000.;
35 | out("Concurrent thread time, sec: %.3f", duration);
36 | concurrentThreadSum += duration;
37 |
38 | if (!MatrixUtil.compare(matrixC, concurrentMatrixC)) {
39 | System.err.println("Comparison failed");
40 | break;
41 | }
42 | count++;
43 | }
44 | executor.shutdown();
45 | out("\nAverage single thread time, sec: %.3f", singleThreadSum / 5.);
46 | out("Average concurrent thread time, sec: %.3f", concurrentThreadSum / 5.);
47 | }
48 |
49 | private static void out(String format, double ms) {
50 | System.out.println(String.format(format, ms));
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/ru/javaops/masterjava/matrix/MatrixUtil.java:
--------------------------------------------------------------------------------
1 | package ru.javaops.masterjava.matrix;
2 |
3 | import java.util.Random;
4 | import java.util.concurrent.ExecutionException;
5 | import java.util.concurrent.ExecutorService;
6 |
7 | /**
8 | * gkislin
9 | * 03.07.2016
10 | */
11 | public class MatrixUtil {
12 |
13 | // TODO implement parallel multiplication matrixA*matrixB
14 | public static int[][] concurrentMultiply(int[][] matrixA, int[][] matrixB, ExecutorService executor) throws InterruptedException, ExecutionException {
15 | final int matrixSize = matrixA.length;
16 | final int[][] matrixC = new int[matrixSize][matrixSize];
17 |
18 | return matrixC;
19 | }
20 |
21 | // TODO optimize by https://habrahabr.ru/post/114797/
22 | public static int[][] singleThreadMultiply(int[][] matrixA, int[][] matrixB) {
23 | final int matrixSize = matrixA.length;
24 | final int[][] matrixC = new int[matrixSize][matrixSize];
25 |
26 | for (int i = 0; i < matrixSize; i++) {
27 | for (int j = 0; j < matrixSize; j++) {
28 | int sum = 0;
29 | for (int k = 0; k < matrixSize; k++) {
30 | sum += matrixA[i][k] * matrixB[k][j];
31 | }
32 | matrixC[i][j] = sum;
33 | }
34 | }
35 | return matrixC;
36 | }
37 |
38 | public static int[][] create(int size) {
39 | int[][] matrix = new int[size][size];
40 | Random rn = new Random();
41 |
42 | for (int i = 0; i < size; i++) {
43 | for (int j = 0; j < size; j++) {
44 | matrix[i][j] = rn.nextInt(10);
45 | }
46 | }
47 | return matrix;
48 | }
49 |
50 | public static boolean compare(int[][] matrixA, int[][] matrixB) {
51 | final int matrixSize = matrixA.length;
52 | for (int i = 0; i < matrixSize; i++) {
53 | for (int j = 0; j < matrixSize; j++) {
54 | if (matrixA[i][j] != matrixB[i][j]) {
55 | return false;
56 | }
57 | }
58 | }
59 | return true;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/ru/javaops/masterjava/service/MailService.java:
--------------------------------------------------------------------------------
1 | package ru.javaops.masterjava.service;
2 |
3 | import java.util.Collections;
4 | import java.util.List;
5 | import java.util.Set;
6 |
7 | public class MailService {
8 | private static final String OK = "OK";
9 |
10 | private static final String INTERRUPTED_BY_FAULTS_NUMBER = "+++ Interrupted by faults number";
11 | private static final String INTERRUPTED_BY_TIMEOUT = "+++ Interrupted by timeout";
12 | private static final String INTERRUPTED_EXCEPTION = "+++ InterruptedException";
13 |
14 | public GroupResult sendToList(final String template, final Set emails) throws Exception {
15 | return new GroupResult(0, Collections.emptyList(), null);
16 | }
17 |
18 |
19 | // dummy realization
20 | public MailResult sendToUser(String template, String email) throws Exception {
21 | try {
22 | Thread.sleep(500); //delay
23 | } catch (InterruptedException e) {
24 | // log cancel;
25 | return null;
26 | }
27 | return Math.random() < 0.7 ? MailResult.ok(email) : MailResult.error(email, "Error");
28 | }
29 |
30 | public static class MailResult {
31 | private final String email;
32 | private final String result;
33 |
34 | private static MailResult ok(String email) {
35 | return new MailResult(email, OK);
36 | }
37 |
38 | private static MailResult error(String email, String error) {
39 | return new MailResult(email, error);
40 | }
41 |
42 | public boolean isOk() {
43 | return OK.equals(result);
44 | }
45 |
46 | private MailResult(String email, String cause) {
47 | this.email = email;
48 | this.result = cause;
49 | }
50 |
51 | @Override
52 | public String toString() {
53 | return '(' + email + ',' + result + ')';
54 | }
55 | }
56 |
57 | public static class GroupResult {
58 | private final int success; // number of successfully sent email
59 | private final List failed; // failed emails with causes
60 | private final String failedCause; // global fail cause
61 |
62 | public GroupResult(int success, List failed, String failedCause) {
63 | this.success = success;
64 | this.failed = failed;
65 | this.failedCause = failedCause;
66 | }
67 |
68 | @Override
69 | public String toString() {
70 | return "Success: " + success + '\n' +
71 | "Failed: " + failed.toString() + '\n' +
72 | (failedCause == null ? "" : "Failed cause" + failedCause);
73 | }
74 | }
75 | }
--------------------------------------------------------------------------------