├── .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 | ![image](https://cloud.githubusercontent.com/assets/13649199/23876457/ab01ff0a-084e-11e7-964f-49c90579fac9.png) 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 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 1. Вступление. Многопоточность и параллельность. 35 | ![Concurrent vs Parallel](https://joearms.github.io/images/con_and_par.jpg) 36 | 37 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 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 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 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 | ## ![video](https://cloud.githubusercontent.com/assets/13649199/13672715/06dbc6ce-e6e7-11e5-81a9-04fbddb9e488.png) 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 | ## ![hw](https://cloud.githubusercontent.com/assets/13649199/13672719/09593080-e6e7-11e5-81d1-5cb629c438ca.png) Задание первого занятия 104 | 105 | - Применить оптимизацию к MatrixUtil.singleThreadMultiply 106 | - Реализовать метод `MatrixUtil.concurrentMultiply`, позволяющий многопоточно перемножать квадратные матрицы N*N. 107 | - Количество дочерних потоков ограничено `MainMatrix.THREAD_NUMBER`. 108 | - Добиться того, чтобы на матрице 1000*1000 многопоточная реализация была быстрее однопоточной 109 | 110 | ----- 111 | ## ![error](https://cloud.githubusercontent.com/assets/13649199/13672935/ef09ec1e-e6e7-11e5-9f79-d1641c05cbe6.png) Подсказки по 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 | } --------------------------------------------------------------------------------