Посадка на рейс "Серьезное изучение Java group #2" завершается.
Мы провели Два дня открытых дверей (видеозапись последнего можно посмотреть тут: https://www.youtube.com/watch?v=vQFxPyLt6lc), разыграли 4 бесплатных места в новой группе, рассказывали о "фишках" Java в постах #deepjava, активно знакомили пользователей с нашим продуктом и рассказывали, почему мы больше, чем просто обучающие курсы, отвечали на вопросы и делали много-много всего, чтобы наши новые студенты получили хорошие знания и возможности профессионального и карьерного роста.
И вот новая группа сформирована и начнет занятия уже завтра! Мы желаем ребятам успехов в обучении. Энтузиазма, жажды знаний и приятного чувства от утоления этой жажды. Желаем классных проектов, драйва и позитива.
Что дальше?
Сегодня еще есть шанс присоединиться к новой группе: https://otus.ru/lessons?course=1?utm_source=telegram и начать заниматься с завтрашнего дня.
Для тех, кто делает свои первые шаги в Java и не смог сдать вступительное тестирование, мы готовим обучающие материалы, которые помогут подготовиться к набору в новую группу по Java, который будет, скорее всего, осенью (т.к. летом мы планируем запуск курсов по другим специальностям). О готовности материалов мы обязательно сообщим.
Спасибо, что вы с нами!
Мы провели Два дня открытых дверей (видеозапись последнего можно посмотреть тут: https://www.youtube.com/watch?v=vQFxPyLt6lc), разыграли 4 бесплатных места в новой группе, рассказывали о "фишках" Java в постах #deepjava, активно знакомили пользователей с нашим продуктом и рассказывали, почему мы больше, чем просто обучающие курсы, отвечали на вопросы и делали много-много всего, чтобы наши новые студенты получили хорошие знания и возможности профессионального и карьерного роста.
И вот новая группа сформирована и начнет занятия уже завтра! Мы желаем ребятам успехов в обучении. Энтузиазма, жажды знаний и приятного чувства от утоления этой жажды. Желаем классных проектов, драйва и позитива.
Что дальше?
Сегодня еще есть шанс присоединиться к новой группе: https://otus.ru/lessons?course=1?utm_source=telegram и начать заниматься с завтрашнего дня.
Для тех, кто делает свои первые шаги в Java и не смог сдать вступительное тестирование, мы готовим обучающие материалы, которые помогут подготовиться к набору в новую группу по Java, который будет, скорее всего, осенью (т.к. летом мы планируем запуск курсов по другим специальностям). О готовности материалов мы обязательно сообщим.
Спасибо, что вы с нами!
YouTube
Всё о курсе «Разработчик Java»
День Открытых Дверей — отличная возможность узнать подробнее о программе курса, особенностях онлайн-формата, навыках, компетенциях и перспективах, которые ждут выпускников после обучения. Также преподаватель расскажет о своём профессиональном опыте и ответит…
Вам нравились наши посты с хэштегом #deepjava? Очень надеемся, что да, потому что нам очень нравится делиться полезной информацией :)
В этом месяце (до начала обучения новой группы по Python) мы хотим погружать вас в тонкости мира Python. Поэтому совсем скоро мы начнем серию постов про #deeppython!
Любителей Java обижать не будем - посты про #deepjava мы все равно будем публиковать, правда, реже.
Знание - само по себе сила!
В этом месяце (до начала обучения новой группы по Python) мы хотим погружать вас в тонкости мира Python. Поэтому совсем скоро мы начнем серию постов про #deeppython!
Любителей Java обижать не будем - посты про #deepjava мы все равно будем публиковать, правда, реже.
Знание - само по себе сила!
#deepjava #otus
Рано или поздно Java разработчик задает себе вопрос: Hibernate или MyBatis? MyBatis или Hibernate? От ответа зависит архитектура проекта, а ответ, в свою очередь, зависит от задачи. Давайте сегодня разберемся, что они такое и когда какой лучше.
Итак, Hibernate это ORM framework. Его полное название Hibernate ORM. Он полностью поддерживает JPA и, фактически, является имплементацией JPA. Его основная задача -- понять как размечены ваши классы аннотациями ORM, построить по ним схему и собирать объекты по строкам из базы. Hibernate сам пишет за вас запросы к базе. Для вас работа с базой выглядит как работа с объектами. Сохранить объект, загрузить объект, обновить объект. Как, собственно, и должно быть. Это же Object Relational Mapping.
MyBatis это Java persistence framework. Не ORM. MyBatis связывает методы интерфейса маппера с SQL запросом. MyBatis не умеет создавать схему. И, честно говоря, вообще ничего о схеме не знает. MyBatis превращает вызов метода в запрос к базе, и как результат вызова метода возвращает результат запроса.
Что лучше подходит для вашего проекта? Смотрите сами:
Если у вас много простых объектов без сложных связей друг с другом -- Hibernate.
Если у вас сложные запросы к базе на агрегацию данных -- MyBatis.
Если вы готовы поручить фреймворку создавать и обновлять для вас схему -- Hibernate.
Если у вас работа с хранимыми процедурами -- MyBatis.
Если вы не хотите писать запросы сами, и работать с JPQL -- HIbernate.
Если вы хотите писать свой ORM (а его так или иначе придется писать) -- MyBatis.
Можно попробовать использовать оба фреймворка в одном проекте. Но мы такого на практике не встречали. Поэтому рано или поздно Java разработчик встает перед вопросом: Hibernate или MyBatis?
Рано или поздно Java разработчик задает себе вопрос: Hibernate или MyBatis? MyBatis или Hibernate? От ответа зависит архитектура проекта, а ответ, в свою очередь, зависит от задачи. Давайте сегодня разберемся, что они такое и когда какой лучше.
Итак, Hibernate это ORM framework. Его полное название Hibernate ORM. Он полностью поддерживает JPA и, фактически, является имплементацией JPA. Его основная задача -- понять как размечены ваши классы аннотациями ORM, построить по ним схему и собирать объекты по строкам из базы. Hibernate сам пишет за вас запросы к базе. Для вас работа с базой выглядит как работа с объектами. Сохранить объект, загрузить объект, обновить объект. Как, собственно, и должно быть. Это же Object Relational Mapping.
MyBatis это Java persistence framework. Не ORM. MyBatis связывает методы интерфейса маппера с SQL запросом. MyBatis не умеет создавать схему. И, честно говоря, вообще ничего о схеме не знает. MyBatis превращает вызов метода в запрос к базе, и как результат вызова метода возвращает результат запроса.
Что лучше подходит для вашего проекта? Смотрите сами:
Если у вас много простых объектов без сложных связей друг с другом -- Hibernate.
Если у вас сложные запросы к базе на агрегацию данных -- MyBatis.
Если вы готовы поручить фреймворку создавать и обновлять для вас схему -- Hibernate.
Если у вас работа с хранимыми процедурами -- MyBatis.
Если вы не хотите писать запросы сами, и работать с JPQL -- HIbernate.
Если вы хотите писать свой ORM (а его так или иначе придется писать) -- MyBatis.
Можно попробовать использовать оба фреймворка в одном проекте. Но мы такого на практике не встречали. Поэтому рано или поздно Java разработчик встает перед вопросом: Hibernate или MyBatis?
#deepjava #otus
Приходилось ли вам писать Java приложения без функции
public static void main(String[] args){...}?
На первый взгляд может показаться, что такое приложение бессмысленно. Ведь его нельзя запустить. Точнее его нельзя запустить через вызов java -jar name.jar. И тем не менее, многие Java разработчики регулярно пишут такие приложения. И запаковывают их не в jar файлы, а в… war файлы. Давайте сегодня с этими war файлами и разберемся.
Продолжая открытый вопрос про запуск приложения нужно отметить, что его код нельзя исполнить в его собственном потоке main. Но мы можем исполнить его в других потоках. По аналогии с библиотеками: библиотека не запускает себя сама, вы запускаете библиотеку в собственных потоках. Ваше приложение может быть “библиотекой” для другого приложения. И в этом случае, другое приложение называют application server. Application server запускает ваше приложение в собственных потоках. Для него ваш код как актеры для Голливуда. Не актеры звонят в Голливуд. Голливуд звонит актерам. Таким образом, вы пишите приложения не с использованием библиотек, а для application server-а.
В общем случае application server должен быть написан по спецификации Java EE. Но есть частные случаи, которые поддерживают только работу веб сервера и сервлетов. Их называют веб серверы и сервлет-контейнеры. Вот для них, как раз, Java разработчики и создают war файлы.
Итак, war или WebARchive это jar, но в отличие от обычного в нем:
Нет мета информации о методе main, с выполнения которого должно начинаться выполнение приложения.
Есть директория WEB-INF и в ней web.xml -- это файл с инструкциями для сервлет-контейнера.
Есть сервлеты. Без них war файл практически бесполезен.
Могут быть файлы статических страниц. Да-да jar в котором в корне лежат index.html, index.js и index.css :о)
Приготовить такой war файл можно при помощи плагина maven-war-plugin к maven. А запускать в любом удобном вам сервлет-контейнере, например в Tomcat или Jetty, просто копированием war файла в директорию webapps. Только при копировании не забудьте переименовать его в root.war. Интересно зачем? Мы и это на занятиях разбираем.
Приходилось ли вам писать Java приложения без функции
public static void main(String[] args){...}?
На первый взгляд может показаться, что такое приложение бессмысленно. Ведь его нельзя запустить. Точнее его нельзя запустить через вызов java -jar name.jar. И тем не менее, многие Java разработчики регулярно пишут такие приложения. И запаковывают их не в jar файлы, а в… war файлы. Давайте сегодня с этими war файлами и разберемся.
Продолжая открытый вопрос про запуск приложения нужно отметить, что его код нельзя исполнить в его собственном потоке main. Но мы можем исполнить его в других потоках. По аналогии с библиотеками: библиотека не запускает себя сама, вы запускаете библиотеку в собственных потоках. Ваше приложение может быть “библиотекой” для другого приложения. И в этом случае, другое приложение называют application server. Application server запускает ваше приложение в собственных потоках. Для него ваш код как актеры для Голливуда. Не актеры звонят в Голливуд. Голливуд звонит актерам. Таким образом, вы пишите приложения не с использованием библиотек, а для application server-а.
В общем случае application server должен быть написан по спецификации Java EE. Но есть частные случаи, которые поддерживают только работу веб сервера и сервлетов. Их называют веб серверы и сервлет-контейнеры. Вот для них, как раз, Java разработчики и создают war файлы.
Итак, war или WebARchive это jar, но в отличие от обычного в нем:
Нет мета информации о методе main, с выполнения которого должно начинаться выполнение приложения.
Есть директория WEB-INF и в ней web.xml -- это файл с инструкциями для сервлет-контейнера.
Есть сервлеты. Без них war файл практически бесполезен.
Могут быть файлы статических страниц. Да-да jar в котором в корне лежат index.html, index.js и index.css :о)
Приготовить такой war файл можно при помощи плагина maven-war-plugin к maven. А запускать в любом удобном вам сервлет-контейнере, например в Tomcat или Jetty, просто копированием war файла в директорию webapps. Только при копировании не забудьте переименовать его в root.war. Интересно зачем? Мы и это на занятиях разбираем.
#deepjava #otus
Принято считать, что многопоточность (multithreading) одна из самых сложных тем в программировании. Давайте разберемся сегодня, что именно в ней сложно, и почему так много разработчиков делают ошибки при разработке приложений, которые работают более чем в одном потоке.
Начнем с того, что в многопоточности… просто. Очень просто, по крайней мере в Java, создать еще один поток. Что такое поток в Java? Как и все остальное, поток в Java это объект. Создать объект потока совсем не сложно: Thread thread = new Thread(); Что в этом объекте особенного? То, что у него есть методы start() и run(). Если, например в методе main(), вызвать у объекта потока метод start(), то через некоторое время у него будет вызван метод run(). И этот вызов будет иметь новый Stack и команды метода run() могут быть выполнены физически в одно и тоже время, что и команды метода main(). То есть… в другом потоке. И в этом первая сложность многопоточности -- поток это объект и поток это последовательность команд. Команд метода run() объекта потока.
Вторая сложность многопоточности в непредсказуемости порядка некоторых событий. Допустим вы создали 10 новых потоков, пронумеровали их и вызвали у них методы start(). Будут ли методы run() этих объектов выполнены в той же последовательности что вы задали при нумерации? Вообще говоря -- нет. То, в какой последовательности будут выполнены методы run() решает… операционная система. И у вас есть только очень опосредованные способы влияния на порядок выполнения (например, через приоритеты).
Ну и самая большая сложность многопоточности это взаимодействие потоков. Если у вас есть задача, которую можно сделать в отдельном потоке, не дожидаясь ее завершения и игнорируя ее результат (например: записать что-то в лог; послать по UDP данные; обработать запрос пользователя, прочитать ответ в базе и отправить пользователю), то многопоточность это легко и весело.
Проблемы начинаются когда несколько потоков хотят взаимодействовать между собой через общую память. Например, если один поток пишет данные, а другой читает. То есть, один меняет общий объект, а второй, в это же время, обращается к полям общего объекта. Ошибки приложения, которые при этом происходят, относят к одному из двух типов: race condition и memory consistency errors. Что это, и как с ними бороться, мы рассмотрим в следующем посте, а более подробно на нашем курсе https://otus.ru/lessons/1?utm_source=telegram&utm_medium=internall&utm_campaign=java&utm_content=deeppost&utm_term=10.08 Присоединяйтесь!
Принято считать, что многопоточность (multithreading) одна из самых сложных тем в программировании. Давайте разберемся сегодня, что именно в ней сложно, и почему так много разработчиков делают ошибки при разработке приложений, которые работают более чем в одном потоке.
Начнем с того, что в многопоточности… просто. Очень просто, по крайней мере в Java, создать еще один поток. Что такое поток в Java? Как и все остальное, поток в Java это объект. Создать объект потока совсем не сложно: Thread thread = new Thread(); Что в этом объекте особенного? То, что у него есть методы start() и run(). Если, например в методе main(), вызвать у объекта потока метод start(), то через некоторое время у него будет вызван метод run(). И этот вызов будет иметь новый Stack и команды метода run() могут быть выполнены физически в одно и тоже время, что и команды метода main(). То есть… в другом потоке. И в этом первая сложность многопоточности -- поток это объект и поток это последовательность команд. Команд метода run() объекта потока.
Вторая сложность многопоточности в непредсказуемости порядка некоторых событий. Допустим вы создали 10 новых потоков, пронумеровали их и вызвали у них методы start(). Будут ли методы run() этих объектов выполнены в той же последовательности что вы задали при нумерации? Вообще говоря -- нет. То, в какой последовательности будут выполнены методы run() решает… операционная система. И у вас есть только очень опосредованные способы влияния на порядок выполнения (например, через приоритеты).
Ну и самая большая сложность многопоточности это взаимодействие потоков. Если у вас есть задача, которую можно сделать в отдельном потоке, не дожидаясь ее завершения и игнорируя ее результат (например: записать что-то в лог; послать по UDP данные; обработать запрос пользователя, прочитать ответ в базе и отправить пользователю), то многопоточность это легко и весело.
Проблемы начинаются когда несколько потоков хотят взаимодействовать между собой через общую память. Например, если один поток пишет данные, а другой читает. То есть, один меняет общий объект, а второй, в это же время, обращается к полям общего объекта. Ошибки приложения, которые при этом происходят, относят к одному из двух типов: race condition и memory consistency errors. Что это, и как с ними бороться, мы рассмотрим в следующем посте, а более подробно на нашем курсе https://otus.ru/lessons/1?utm_source=telegram&utm_medium=internall&utm_campaign=java&utm_content=deeppost&utm_term=10.08 Присоединяйтесь!
otus.ru
Курсы программирования на Java, онлайн курс по Java разработке, курсы по Java, курсы «Джава». Запишись на курсы программирования…
Мы выпускаем после наших курсов крутых Java программистов. Уникальное обучение языку программирования основаному на джава, с возможностью трудоустройства
#deepjava #otus
О чем говорят логи Garbage Collector
Наверняка вы слышали, что сборщик мусора в Java может оказывать значительное влияние на производительность приложения. Многое может зависеть от типа сборщика и его настройки. Есть много инструментов для того, чтобы мониторить различные параметры сборки, но иногда достаточно внимательно посмотреть на логи, которые пишет GC. В этой заметке я расскажу, как выглядят логи, которые пишет сборщик мусора и что с помощью них можно понять о работе вашего приложения. Для начала, нужно запустить JVM, указав специальные параметры:
-XX:+PrintGCDetails - печатать детали о событиях сборки мусора
-XX:+PrintGCDateStamps - также печатать timestamp этих событий
-Xloggc:/home/otus/gc.log - опционально можно указать, в какой файл будут писаться логи, чтобы отделить их от логов вашего приложения.
Сборщики мусора SerialGC, ParallelGC, ConcurrentMarkSweepGC (CMS) разбивают память (хип) java-приложения на несколько регионов. Это Eden+Survivor1+Survivor2 - молодое поколение и Tenured - старое поколение. Сборщик GC1 устроен иначе и его стоит рассматривать отдельно.
Сборки мусора могут происходить только в молодом поколении - Minor GC или во всех регионах - FullGC. Давайте посмотрим на логи на примере ParallelGC (-XX:+UseParallelGC)
В этих логах отображено 3 сборки мусора, сначала 2 minor, затем full:
2017-09-17T21:03:30.200+0300: 0,449: [GC (Allocation Failure) [PSYoungGen: 3662K->336K(4608K)] 3662K->3408K(15872K), 0,0020199 secs] [Times: user=0,01 sys=0,00, real=0,01 secs]
2017-09-17T21:03:30.506+0300: 0,755: [GC (Allocation Failure) [PSYoungGen: 3652K->400K(4608K)] 6724K->6544K(15872K), 0,0021768 secs] [Times: user=0,01 sys=0,00, real=0,00 secs]
017-09-17T21:03:30.815+0300: 1,064: [Full GC (Ergonomics) [PSYoungGen: 400K->0K(4608K)] [ParOldGen: 9216K->9581K(18944K)] 9616K->9581K(23552K), [Metaspace: 3570K->3570K(1056768K)], 0,0047284 secs] [Times: user=0,00 sys=0,00, real=0,01 secs]
2017-09-17T21:03:30.200+0300 - сперва идет timestamp - абсолютное время, когда сборка была начата, затем время относительно старта приложения (0,449)
GC (AllocationFailure) - укзаывает, что это минорная сборка, при полной сборке будет указано Full GC. Причина начала сборки: не удалось выделить (allocate) место под новый объект
PSYoungGen - тип сборщика. PSYoungGen - это сборка молодого поколения в ParallelGC. Также вы можете встретить DefNew - сборка молодого поколения в SerialGC, ParNew - сборка молодого поколения CMS
Дальше идет самая интересная с практической точки зрения часть - занятая память до и после сборки по регионам:
[PSYoungGen: 3662K->336K(4608K)] - В молодом поколении до сборки было 3662K, после - 336K. Всего в регионе доступно памяти - 4608K
3662K->3408K(15872K) - Статистика по всему хипу, доступно 15872K. И здесь мы видим интересный момент, что в молодом поколении освободилось 3326K, а общее место в хипе уменьшилось только на 3662 - 3408 = 254К. Это означает, что часть объектов были перемещены из молодого поколения в старое (promoted).
Сборка заняла 0,0020199 secs
Для FullGC в логах видно статистику по всем регионам памяти, так как сборка запускается и в молодом и в старом поколении.
[PSYoungGen: 400K->0K(4608K)] [ParOldGen: 9216K->9581K(18944K)] 9616K->9581K(23552K), [Metaspace: 3570K->3570K(1056768K)], 0,0047284 secs]
[Times: user=0,01 sys=0,00, real=0,01 secs]
User - user-space время (операции вне ядра ОС), затраченное на GC
Sys - kernel-space - время, затраченное на системные вызовы ОС
Real - реальное время от начала и до конца сборки мусора. В нем учитывается, то время, пока процесс был прерван ОС или заблокирован (например, на IO)
При использовании параллельной сборки User-space время может быть больше чем real-time, потому что user-space будет суммироваться по всем CPU, на которых исполнялась сборка.
О чем говорят логи Garbage Collector
Наверняка вы слышали, что сборщик мусора в Java может оказывать значительное влияние на производительность приложения. Многое может зависеть от типа сборщика и его настройки. Есть много инструментов для того, чтобы мониторить различные параметры сборки, но иногда достаточно внимательно посмотреть на логи, которые пишет GC. В этой заметке я расскажу, как выглядят логи, которые пишет сборщик мусора и что с помощью них можно понять о работе вашего приложения. Для начала, нужно запустить JVM, указав специальные параметры:
-XX:+PrintGCDetails - печатать детали о событиях сборки мусора
-XX:+PrintGCDateStamps - также печатать timestamp этих событий
-Xloggc:/home/otus/gc.log - опционально можно указать, в какой файл будут писаться логи, чтобы отделить их от логов вашего приложения.
Сборщики мусора SerialGC, ParallelGC, ConcurrentMarkSweepGC (CMS) разбивают память (хип) java-приложения на несколько регионов. Это Eden+Survivor1+Survivor2 - молодое поколение и Tenured - старое поколение. Сборщик GC1 устроен иначе и его стоит рассматривать отдельно.
Сборки мусора могут происходить только в молодом поколении - Minor GC или во всех регионах - FullGC. Давайте посмотрим на логи на примере ParallelGC (-XX:+UseParallelGC)
В этих логах отображено 3 сборки мусора, сначала 2 minor, затем full:
2017-09-17T21:03:30.200+0300: 0,449: [GC (Allocation Failure) [PSYoungGen: 3662K->336K(4608K)] 3662K->3408K(15872K), 0,0020199 secs] [Times: user=0,01 sys=0,00, real=0,01 secs]
2017-09-17T21:03:30.506+0300: 0,755: [GC (Allocation Failure) [PSYoungGen: 3652K->400K(4608K)] 6724K->6544K(15872K), 0,0021768 secs] [Times: user=0,01 sys=0,00, real=0,00 secs]
017-09-17T21:03:30.815+0300: 1,064: [Full GC (Ergonomics) [PSYoungGen: 400K->0K(4608K)] [ParOldGen: 9216K->9581K(18944K)] 9616K->9581K(23552K), [Metaspace: 3570K->3570K(1056768K)], 0,0047284 secs] [Times: user=0,00 sys=0,00, real=0,01 secs]
2017-09-17T21:03:30.200+0300 - сперва идет timestamp - абсолютное время, когда сборка была начата, затем время относительно старта приложения (0,449)
GC (AllocationFailure) - укзаывает, что это минорная сборка, при полной сборке будет указано Full GC. Причина начала сборки: не удалось выделить (allocate) место под новый объект
PSYoungGen - тип сборщика. PSYoungGen - это сборка молодого поколения в ParallelGC. Также вы можете встретить DefNew - сборка молодого поколения в SerialGC, ParNew - сборка молодого поколения CMS
Дальше идет самая интересная с практической точки зрения часть - занятая память до и после сборки по регионам:
[PSYoungGen: 3662K->336K(4608K)] - В молодом поколении до сборки было 3662K, после - 336K. Всего в регионе доступно памяти - 4608K
3662K->3408K(15872K) - Статистика по всему хипу, доступно 15872K. И здесь мы видим интересный момент, что в молодом поколении освободилось 3326K, а общее место в хипе уменьшилось только на 3662 - 3408 = 254К. Это означает, что часть объектов были перемещены из молодого поколения в старое (promoted).
Сборка заняла 0,0020199 secs
Для FullGC в логах видно статистику по всем регионам памяти, так как сборка запускается и в молодом и в старом поколении.
[PSYoungGen: 400K->0K(4608K)] [ParOldGen: 9216K->9581K(18944K)] 9616K->9581K(23552K), [Metaspace: 3570K->3570K(1056768K)], 0,0047284 secs]
[Times: user=0,01 sys=0,00, real=0,01 secs]
User - user-space время (операции вне ядра ОС), затраченное на GC
Sys - kernel-space - время, затраченное на системные вызовы ОС
Real - реальное время от начала и до конца сборки мусора. В нем учитывается, то время, пока процесс был прерван ОС или заблокирован (например, на IO)
При использовании параллельной сборки User-space время может быть больше чем real-time, потому что user-space будет суммироваться по всем CPU, на которых исполнялась сборка.
#deepjava #otus
Принято считать, что многопоточность (multithreading) одна из самых сложных тем в программировании. И мы решили посвятить ей не одну, а несколько заметок, которые вы сможете найти по хэштегу #deepjava.
В этой заметке мы разберем типы ошибок многопоточного доступа к данным: race condition и memory consistency errors.
Но, перед тем как обсуждать ошибки доступа, давайте сначала разберем, что такое многопоточный доступ к данным. В какой именно ситуации можно получить такие ошибки.
Мы уже упоминали в предыдущем посте, что поток в Java это объект. У любого объекта есть класс. В классе могут быть методы и переменные. Представьте, что у вас есть класс — наследник от Thread, в котором вы в одной из переменных храните ссылку на массив. И этот массив вы получаете в конструкторе класса.
Пусть теперь, в runtime вы создаете два объекта рассмотренного выше класса и передаете в оба один и тот же массив. К элементам этого массива вы можете обращаться в методах run() ваших объектов. Одновременно. Из разных потоков исполнения. Вот это и есть многопоточный доступ к данным которые хранит массив.
Например, один поток может писать что-то в массив, а другой читать из него.
Рассмотрим теперь ситуацию, когда два рассмотренных выше потока собираются увеличить значение числа, которое записано в первой ячейке массива. Со следующей последовательностью событий: первый поток прочитал значение и увеличил его, второй поток прочитал то же значение, первый записал новое, второй увеличил значение и записал его. В результате вместо ожидаемого увеличения значения на 2 мы получим увеличение на 1, так как результат работы первого потока был “перетерт” результатом работы второго. Такая ситуация происходит из-за неатомарности операции увеличения значения числа. И является разновидностью ошибки многопоточного доступа — race condition.
Вторая возможная ошибка многопоточного доступа — memory consistency error происходит из-за того, что разные потоки могут быть физически исполнены на различных процессорах вашего компьютера. Каждый процессор может закэшировать значение переменной у себя, не записывая ее в общую память. В результате разные потоки могут видеть в одно и тоже время разное значение переменной.
Описанные выше проблемы призвана решить Java Memory Model. Что это такое и как именно она может помочь разработчику, мы рассмотрим в следующих заметках. И, подробно разберем на занятиях курса “Разработчик Java” в OTUS о которых вы можете узнать подробнее перейдя по ссылке:
otus.ru/promo/java-2017/?utm_source=telegram&utm_medium=internal&utm_campaign=java&utm_content=deeppost&utm_term=27.09
Принято считать, что многопоточность (multithreading) одна из самых сложных тем в программировании. И мы решили посвятить ей не одну, а несколько заметок, которые вы сможете найти по хэштегу #deepjava.
В этой заметке мы разберем типы ошибок многопоточного доступа к данным: race condition и memory consistency errors.
Но, перед тем как обсуждать ошибки доступа, давайте сначала разберем, что такое многопоточный доступ к данным. В какой именно ситуации можно получить такие ошибки.
Мы уже упоминали в предыдущем посте, что поток в Java это объект. У любого объекта есть класс. В классе могут быть методы и переменные. Представьте, что у вас есть класс — наследник от Thread, в котором вы в одной из переменных храните ссылку на массив. И этот массив вы получаете в конструкторе класса.
Пусть теперь, в runtime вы создаете два объекта рассмотренного выше класса и передаете в оба один и тот же массив. К элементам этого массива вы можете обращаться в методах run() ваших объектов. Одновременно. Из разных потоков исполнения. Вот это и есть многопоточный доступ к данным которые хранит массив.
Например, один поток может писать что-то в массив, а другой читать из него.
Рассмотрим теперь ситуацию, когда два рассмотренных выше потока собираются увеличить значение числа, которое записано в первой ячейке массива. Со следующей последовательностью событий: первый поток прочитал значение и увеличил его, второй поток прочитал то же значение, первый записал новое, второй увеличил значение и записал его. В результате вместо ожидаемого увеличения значения на 2 мы получим увеличение на 1, так как результат работы первого потока был “перетерт” результатом работы второго. Такая ситуация происходит из-за неатомарности операции увеличения значения числа. И является разновидностью ошибки многопоточного доступа — race condition.
Вторая возможная ошибка многопоточного доступа — memory consistency error происходит из-за того, что разные потоки могут быть физически исполнены на различных процессорах вашего компьютера. Каждый процессор может закэшировать значение переменной у себя, не записывая ее в общую память. В результате разные потоки могут видеть в одно и тоже время разное значение переменной.
Описанные выше проблемы призвана решить Java Memory Model. Что это такое и как именно она может помочь разработчику, мы рассмотрим в следующих заметках. И, подробно разберем на занятиях курса “Разработчик Java” в OTUS о которых вы можете узнать подробнее перейдя по ссылке:
otus.ru/promo/java-2017/?utm_source=telegram&utm_medium=internal&utm_campaign=java&utm_content=deeppost&utm_term=27.09
OTUS: 14 октября 2017 запускаем курс «Разработчик Java»
Профессиональные онлайн курсы для разработчиков
Сегодня в 20:00 последний День Открытых Дверей курса «Разработчик Java»!
Последний шанс выиграть бесплатное место в группе! Чтобы принять участие в розыгрыше, пройдите вступительное тестирование и запишитесь на День Открытых Дверей. До встречи в прямом эфире!
А пока можно прочитать продолжение нашей заметки #deepjava о возможностях и применении CompletableFuture:
Последний шанс выиграть бесплатное место в группе! Чтобы принять участие в розыгрыше, пройдите вступительное тестирование и запишитесь на День Открытых Дверей. До встречи в прямом эфире!
А пока можно прочитать продолжение нашей заметки #deepjava о возможностях и применении CompletableFuture:
«Что под капотом Spring Data JPA» – полезная заметка для подготовки к курсу «Разработчик Java», который стартует 13 апреля!
Читаем вместе: #deepjava
Читаем вместе: #deepjava
Как давно вы писали комментарий в коде? Как часто вы пишите комментарии? Есть ли у вас полиси на их написание? И, самое главное, зачем их писать?
Публикуем полезную заметку Виталия Чибрикова, преподавателя курса «Разработчик Java»: #deepjava
Публикуем полезную заметку Виталия Чибрикова, преподавателя курса «Разработчик Java»: #deepjava