понедельник, 12 декабря 2011 г.

Бесплатный хостинг в amazon ec2

Удивительно, но при желании можно легко получить собственный виртуальный сервер в амазоновском облаке EC2 практически без затрат денег.

Мотивация

Для чего это может быть нужно?
  • поднять свой прототип сайта, проскейлить его если вырастет нагрузка
  • повесить себе прокси
  • хостить блог, картинки итп
  • просто держать бэкапы в облаке (S3)
  • создать софтовый RAID поверх S3 хранилища
  • сделать примерный образ желаемой машины, и расклонировать ее на 100 нодов, причем за некоторые можно платить как за обязательные, а другие будут запускаться только при определенной нагрузке

Тарифы

У amazon'a есть различные типы инстансов. Бесплатен Micro:
Micro Instance
--------------
613 MB memory
Up to 2 EC2 Compute Units (for short periodic bursts)
EBS storage only
32-bit or 64-bit platform
I/O Performance: Low
API name: t1.micro
На него действуют следующие ограничения:
AWS Free Usage Tier (Per Month):
--------------
750 hours of Amazon EC2 Linux Micro Instance usage 
    (613 MB of memory and 32-bit and 64-bit platform support)
    – enough hours to run continuously each month*
750 hours of an Elastic Load Balancer plus 15 GB data processing*
10 GB of Amazon Elastic Block Storage, plus 1 million I/Os and 1 GB of snapshot storage*
5 GB of Amazon S3 standard storage, 20,000 Get Requests, and 2,000 Put Requests*
15 GB of bandwidth out aggregated across all AWS services*
25 Amazon SimpleDB Machine Hours and 1 GB of Storage**
100,000 Requests of Amazon Simple Queue Service**
100,000 Requests, 100,000 HTTP notifications 
1,000 email notifications for Amazon Simple Notification Service**
10 Amazon Cloudwatch metrics, 10 alarms, and 1,000,000 API requests**
На более серьезный setup можно прикинуть расходы в этом калькуляторе.
Если очень грубо, то за 60$ в мес можно получить 1.7Ghz x 1Core, 2Gb ram, 100Gb места и копеечный траффик.

Настройка

Ставим putty и puttygen отсюда

Создаем аккаунт в amazon через admin console. Для этого понадобится действующая кредитка VISA или MasterCard. Как и многие другие магазины они ее проверяют списывая 1 USD.

Далее

Выбираем регион (самый ближайший - IRELAND)
Жмем кнопку Launch instance
Выбираем ОС, по умолчанию предлагают Basic 32-bit Amazon Linux AMI (бесплатный - только linux). При желании поставить LAMP сразу можно ткнуть вкладку Community AMIs и найти там что-то из этого списка готовых образов. Также можно и windows но это дороже.
На вкладке Instance details проверяем что мы делаем Micro инстанс (t1.micro); вводим имя хоста.
Создаем пару ключей для авторизации чз Putty. Скачиваем pem-файлик.
Создаем новую группу безопасности: в поле type = ssh, source = 0.0.0.0/0, жмем add rule.
Идем на вкладку Instances, как только сервер запущен мы сможем залезть в консоль по ssh.
Ура.. Теперь у нас есть свой сервер :].

Теперь цепляемся по ssh к нему.
Запускаем Puttygen, открываем в нем скачанный pem-файл, жмем кнопку import.
Находим dns - имя хоста в админ консоли.
Запускаем путти, коннектится будем под именем ec2-user, поэтому коннект лучше называть ec2-user@dns-host-name.
В свойствах соединения, в Connection -> SSH -> Auth добавляем *.ppk файл сгенеренный нами ранее с помощью puttygen.
Жмем save. Потом соединяемся (user = ec2-user, пароль не нужен.. он в публичном ppk ключе).
А вот и шелл..

суббота, 5 ноября 2011 г.

XML-технологии за 5 минут. XML, XML-NS, Fast Infoset, XPATH, XSLT, XSD, DTD, XML schema, SOAP, WSDL, MTOM, SAAJ, DOM, SAX, STAX, JAXB, dom4J, jdom, xerces, xalan, xsteam, JAX-WS, JAX-RT, SOA, ESB.

      xml В текущем состоянии развелось множество buzz-words связанных с различными фреймворками и обработкой XML. Местами они ничего не значат. Местами суть концепции очень простая – но всё размазано по куче книжек и FAQ-ов. Описание не претендует на 100% верное – это лишь сжатая абстракция, которая сложилась у меня в голове после разработки интеграционного проекта на базе ESB\SOA\ XML \Web Services\BPEL в течение 2х лет. Если где-то сильну вру – поправьте ;)

 

Оглавление
  • XML
    XML
    Well-formed XML
    Valid XML
    DTD
    XML Schema / XSD
    Relax NG
    XML Namespaces
    Xpath
    XSLT
    Binary XML
  • JAVA + XML
    Типы парсеров
    XML фреймворки и парсеры
    Beans-to-XML mapping
  • WEB SERVICES
    SOAP + WSDL
    Передача бинарных данных
    Совместимость
  • JAVA + WEB SERVICES
    JAXWS/METRO
    Apache AXIS
    Apache CXF
    Spring WS
  • SOA / ESB / BPM
    SOA
    ESB
    Задачка из жизни
  • Утилиты для xml



XML



 



XML

суть текстовый формат хранения структурированных данных,     Плюсы

  • структурированный, хорошо мапится на объектные модели
  • Читабелен в редакторе, умеет Unicode
  • Хорошая обратная совместимость, решает проблемы по части интеграции систем на различных ОС\платформах итп, является W3C стандартом.
  • Поддерживает ссылки между сущностями
  • Поддерживает типы данных и валидацию
  • Плохая производительность в сравнении с бинарными форматами
  • Большая избыточность данных
  • Нельзя хранить бинарные данные без перекодировки в BASE64 (+30% места на диске)
 

Well-formed XML

XML который удовлетворяет ограничениям

  • есть корневой элемент
  • все теги правильно вложены друг в друга и закрыты
  • шапка и заголовок файла валидные
  • все спец. символы правильно закодированы с использованием xml entites (всякие ‘&’ итп…) или использована секций CDATA
  • важно понимать что далеко не любые данные можно написать в xml без перекодирования во что-то вроде BASE64
т.е. Well formed = такой XML уже можно парсить парсером.

 



Valid XML

Формулировка означает что данные файла соответствуют некоторой структуре документа или правилам; правила задаются через cпециальный синтаксис – XML Schema или DTD. Valid = такой XML уже можно обрабатывать парсером с включенной валидацией



 



DTD

Это старый формат валидации XML, чем-то напоминает BNF-нотацию объявления синтаксиса. Выглядит примерно так

  • Не имеет нормальных встроенных типов данных
  • Не позволяет делать сложную валидацию
  • Можно втыкать прямо внутрь самого документа (не ссылаясь на внешний ресурс)
еще примеры

 



XML Schema / XSD

Более новый вариант валидации

  • объявляет простые и сложные типы данных, каждый тип может включать в себя другие
  • за счет этого позволяет более формально маппить объекты на xml и валидировать их
  • поддерживает примитивы и ограничения по значению
  • втыкать внутрь документа (embedded) нельзя
SimpleAddress.xsd Test.xml

Relax NG

Альтернативный способ описания струкутры xml, считается более простым чем xml schema. Бывает в 2х видах – XML и compact. Пример compact синтаксиса

 


XML Namespaces

Пространства имен, фича которая появилась в xml позднее и поэтому местами продумана довольно плохо и костыльно. Основная идея в том что любой элемент можен объявить префикс namespace и проассоциировать этот префикс с URL. URL используется просто как уникальный идентификатор Это позволяет в теории не бояться что частям xml не хватит имен в названиях, это активно используется в Xpath и при валидации.

  • элементы из разных namespace’ов с одним названием воспринимаются как разные.
  • у каждого элемента есть default namespace который ему достается по наследству от родительского элемента, при этом уже ничего не нужно указывать – все автоматом получит нужный префикс
Здесь <test/> == <a:test/>
Обучалка по xml namespaces    

Xpath

Язык для выполнения запросов к XML DOM дереву. Достаточно гибкий, но движок запросов, как правило, не очень быстрый. Пример: выбрать все элементы BBB в дереве с атрибутом name равным bbb: выбрать все элементы, являющиеся прямыми потомками /AAA/CCC/DDD Обучалка по XPATH    



XSLT

Язык для работы с XML шаблонами – позволяет выбирать данные, преобразовывать и мержить с другими xml. Чаще всего используется для отделения разметки веб страницы (xhtml) и данных (например таблиц выгруженных в xml) или для процессинга\конвертации xml-файлов. Побочным эффектом такой универсальности является мозго-взрывной синтаксис и совершенно отвратный и нечитаемый результат (имхо). Хотя при должном упорстве язычок поддается изучению, в совершенстве его знают только избранные и некоторые верстальщики. Пример Обучалка по XSLT    



Binary XML

Поскольку XML так плох по части производительности и избыточности хранения, регулярно предпринимаются попытки изобрести более нативное представление \ замену Fast Infoset - цель формата сокращение места и ускорение парсинга. Vtd xml – отличный формат обработки гигабайтный DOM- деревьев.



JAVA + XML

JDK хорошо поддерживает все что есть в XML мире. По дефолту включаются почти все парсеры – SAX, StaX, DOM. С версии 1.4+ JDK поддерживает динамическую регистрацию XML-парсеров. Такие парсеры вызываются внутри JDK при использовании его XMl API. Раньше нужно было добавлять парсер как доп. библиотеку, теперь с 1.4 по дефолту используется XERCES, который переписывают от версии к версии. Важно: из за смены JDK могут меняться\ломаться и сами парсеры – от этого переносимость приложения между разными JDK не такая легкая, как того бы хотелось java-разработчикам.



 



 



Типы парсеров

SAX parser

  • Event-driven парсинг
  • код обрабатывает события такие как: найден начальный тег, найден атрибут, найден конечный тег.
  • Быстрый по производительности, и простой по реализации
  • Тяжело написать сложную логику

DOM parser

  • формируется дерево объектов из элементов с атрибутами;
  • дерево хранится в памяти, его можно крутить и изменять как угодно, удобно работать со сложными структурами
  • удобно вычислять XPATH функции
  • в целях оптимизации некоторые узлы могут не разбираться, пока к ним не обратятся

Pull parser

  • Среднее между DOM и SAX, парсинг управляется кодом, т.е. ему говорят в какую сторону парсить документ и что вытаскивать.
  • Хорошая производительность.
  • Код выходит проще, чем для SAX модели.
Вот такая табличка хорошо сравнивает их по фичам.
Feature StAX SAX DOM TrAX
API Type Pull, streaming Push, streaming In memory tree XSLT Rule
Ease of Use High Medium High Medium
XPath Capability No No Yes Yes
CPU and Memory Efficiency Good Good Varies Varies
Forward Only Yes Yes No No
Read XML Yes Yes Yes Yes
Write XML Yes No Yes Yes
Create, Read, Update, Delete No No Yes No


XML фреймворки и парсеры

Dom4j – лучшее что есть для DOM-парсинга, используется в Intellij IDEA. Сейчас уже дорос до поддержки DOM, SAX , JAXP (встраивается в JDK как парсер по умолчанию), XPATH, XSLT.

Jdom – чуть устаревший предшественник dom4j, хорошая библиотека т.к. всё есть.

xom – очень хорошо продуманная библиотека, приятно пользоваться, умеет много разного. Отдельных похвал заслуживает ее подход к дизайну API.

vtd-xmlсупер быстрый движок для обработки гигабайтных DOM-деревьев, использует собственный бинарный формат для хранения дерева объектов, есть нативные реализации. Один из самых интересных фреймворков из того что я видел.

xerces-j – парсер по умолчанию в JDK1.4+

xalan – популярный XSLT движок, используется в куче разных фреймворков.



 



Beans-to-XML mapping

JAXB – мощная система, входит в JAXP ( в JDK);

  • позволяет задать аннотации на объекте и смаппить его на xml
  • по аннотациям может генерится xsd
  • позволяет грузить из\сохранять в xml инстансы такого объекта
  • используется в стеке вебсервисов JavaEE, поэтому производительность должна быть на уровне
  • богатый функционал и непростое API, поэтому требует время на освоение

Xstream – легкий быстрый и удобный фреймворк для маппинга xml в java-бины

  • практически нулевая сложность настройки
  • чистый xml на выходе, без спец. полей итп мусора
  • must-have для парсинга конфигурационных xml файлов.
  • все что нельзя сделать по умолчанию конфигурируется чз аннотации.
  • умеет сериализовать графы

 

400px-WSDL_11vs20

WEB SERVICES

SOAP – протокол для пересылки сообщений.

  • Определяет 2 основных поля – header и body.
  • Обычно используется в стеке вебсервисов поверх HTTP.

 

WSDL –язык описания веб-сервисов WSDL определяет

  • какие типы данных у нас есть (комплексные типы, на базе xsd-типов),
  • какие сообщения (состоящие из полей нужных типов) могут передаваться\приниматься,
  • какие есть сервисы,
  • какие есть в них порты (endpoints),
  • какие методы есть у каждого из портов.

Пример: Версии

  • soap 1.1 -> wsdl 1.1 (текущие версии связки – используется повсеместно)
  • soap 1.2 -> wsdl 2.0 (используется редко, плохо поддерживается фреймворками)
  • Soap 1.1 vs Soap 1.2 (раз, два, три) , wsdl 1.1 vs wsdl 2.0
Есть много разных способов отображения объектов на SOAP сообщения (SOAP-binding). Различают вот такие варианты:
  1. RPC/encoded
  2. RPC/literal
  3. Document/encoded
  4. Document/literal
  5. Document/literal wrapped
Биндинг по сути определяет что попадет в xml-сообщение: имена параметров? Типы параметров? Имя вызванной процедуры? Итп. Про биндинг детально можно прочитать тут  

Передача бинарных данных

SAAJ – один из стандартов который так и не прижился. MTOM - активно используется, есть во всех популярных JAVA-фреймворках; идея аналогична добавлению вложений в email: после soap сообщения добавляется специальная секция в которую пишутся raw бинарные данные. Прим:

  • mtom не является спекой, ноды м-ду собой должны знать что оба поддерживают mtom и одинаково это понимают.
  • Некоторые реализации могут делать все так как будто mtom корректно поддерживается, но в реальности в конец добавлять xop:include с Base64 данными (+33% размер аттача)…


 



Совместимость

Разные SOAP версии\биндинги не совместимы, например эти связки НЕ будут работать по дефолту:

  • Axis + weblogic
  • Jaxws + ms sharepoint
Разные производители (Microsoft, Sun) в своих веб-сервисах полагаются на различные дефолты.. поэтому иногда бывает непросто дернуть даже обычный веб-сервис.

 



JAVA + WEB SERVICES



 



JAXWS/METRO

Стек веб-сервисов в JavaEE сделан на базе проекта METRO, туда входят JAXB, JAXWS, MTOM, STAX итп.. сама реализация хорошая, быстрая и стабильная. Простой пример: Скачиваем JAXWS RI, добавляем немного аннотаций , получаем веб-сервис который можно запускать прямо из main метода. Запускать можно вот таким кодом



 



Apache AXIS

Популярный и хороший фреймвок, текущая весия 2+, кое-где еще распространен Axis1.x но он не так удобен в использовании.. http://axis.apache.org/axis2/java/core/





 



Apache CXF

Фреймворк рабочий и полноценный, по попользовав его остался крайне недоволен кривой поддержкой некоторых вещей и глючностью. http://cxf.apache.org/



 



Spring WS

Кошерная реализация от SpringSource. Не использовал, но все хвалят. http://static.springsource.org/spring-ws/sites/2.0/  



SOA / ESB / BPM

Все слышали слова SOA , BPM , ESB .. но на самом деле мало кто из заказчиков\PM-ов\руководителей ИТ на самом деле понимает что это всё такое..

Sales рисуют абстрактные картинки.. на которых все хорошо, гибко и чудесно. Но в головах - туман.. и желание потратить немного денег на всё это.. и с этим приходят чтобы “интегрироваться”. Вот хорошая статья как введение в наши проблемы - SOA и BPM



 



SOA

SOA - это очень простая концепция

  • каждая служба это сервис..
  • “давайте сделаем” общий orchestration который свяжет все эти службы между собой в некий сервис..
  • который будет предоставляться конечным пользователям с некоторым качеством (SLA?).
  • всё

Что SOA не делает:

  • SOA это не только +1 к business value: еще есть толстая техническая составляющая которая даст отдачу только чз большой промежуток времени
  • SOA не требует BPM
  • SOA не обязательно требует несколько хостов
  • SOA не обязывает пользоваться messaging или обработкой событий
  • SOA никак не относится к веб-сервисам, REST, XML, RMI итп. это всего лишь протоколы конкретных реализаций.

  Почему SOA это трудно

  • тяжело выделить хорошую, ре-юзабельную службу в отдельный сервис и потом везде использовать
  • повторное использование очень тяжело предусмотреть, особенно если бизнес процессами рулят не-технические люди
  • маркетинг – сам термин SOA завален дурной рекламой от ведущих вендоров.. до такой степени что разобраться в терминах становится очень сложно. Каждый кому не лень переделал свой унылый и кроивой интеграционыый тул (или MOM-сервер) как SOA compatible и продает его..
  • мало внедрений


 



 



ESB

Что такое ESB:

  • это единая архитектура интеграционной шины сделанная в соотв-ии с SOA подходом
  • чаще всего используют веб-сервисы для транспорта
  • чаще всего на шину втыкают движок для исполнения long-running бизнес процессов
  • для общения с внешним миром для каждой внешней системы пишутся адаптеры
  • самая важная функциональность это messaging (отправка сообщений через некоторую общую среду) и routing (управление доставкой сообщений подписанным компонентам) , поверх всего этого у самых крупных вендоров навернуто еще 10 слоев абстракций , но суть от этого не меняется.

Примеры ESB продуктов:

  • MS BizTalk
  • Oracle ESB
  • IBM WebSphere ESB
  • Open ESB
  • Mule
  • Tibco
  • Apache ServiceMix
 

Задачка из жизни

Недавно моим мнением поинтересовались вот в таком кейсе:

 
Задача: у кастомера есть более 40 приложений (и/или интерфейсов к другим системам) для автоматизации своего бизнеса. Приложения вида: вебпортал / десктоп / мобильные / SAP и т.п., написанные на разных языках / платформах. Примерно 10тыс. пользователей этих приложений в стационарных офисах и 1,5тыс. пользователй в мобильных офисах. Постепенно приложения переписываются под технологию .NET (C# / WCF / EF / Silverlight / ASP.NET / MSSQL / etc.). В качестве платформы для обмена данными между приложениями кастомер предлагает (но не настаивает) на BizTalk-е.

Нужно оценить применимость BizTalk и конкурирующих продуктов с точки зрения:
    легкости интеграции с разными приложениями (написанных на Silverlight / ASP.NET / mobile apps)
    скорости обучения девелоперов
    стоимости деплоймента в энтерпрайз виде
    безопасности
    надежности
    скорости работы
    устойчивости к нагрузкам и т.д.

Напишите, если у Вас был опыт работы с BizTalk или его аналогами. В чем принципиальная выгода от использования BizTalk, по сравнению, например, с "самописной" системой обмена данными между приложениями?
Имхо, есть как минимум 3 "самописные" замены BizTalk:

1) написать свой сервер приложений. Т.е. это будет постоянно работающие в режиме 24/7 приложение на выделенном сервере, которое будет уведомлять об изменениях все подписанные на это клиентские приложения.
2) т.к. каждое приложение результаты своей работы складывает в БД (как правило, в  MSSQL) или в виде файлов на ftp сервер, то можно чтобы каждое приложение перодически (раз в несколько минут) опрашивало через вебсервис БД / ftp сервер на предмент наличия важных для него данных.
3) на уровне БД MSSQL в триггере при появлении новых данных в таблице, послать сообщение через .NET CLR stored procedure (WCF + MSMQ?). Для случая с файлами на ftp сервере - написать приложение которое будет периодически проверять каталог и рассылать уведомления при появлении новых файлов (WCF + MSMQ?).

Моё имхо: Плюсы применения BizTalk

  • сколько лет это проживет после того как этот проект завершится, и насколько тяжело будет разбираться потомкам в том что останется
  • вроде как есть графический редактор для orchestrations и готовая модель вида - пишем адаптер для каждой системы в biztalk, внутри biztalk'a ходят наши же сообщения 
  • это легче продать, компании верят в коробочные решения, даже если они утыканы костылями как ёлка опилками. плюс есть туманная вера что они смогут найти другого вендора на поддержку (не вас).

Минусы BizTalk

  • если biztalk медленно работает или чего-то не умеет - проект обрастет костылями, будет медленно работать, будет тяжел в деплойменте итп.
  • не сможете писать юнит тесты, и вообще какие-либо тесты.. это большой "-"
  • если столкнетесь с багами которые MS откажется исправлять - будете плакать но пользоваться.
  • если будете пользоваться рисовалкой "процессов" - рано или поздно модель станет очень сложна в поддержке, т.е. только опытные ассы рискнут ее править, плюс уткнетесь в ограничения самого тула; (вообще это происходит с любым визуальным инструментом при разработке чего-либо сложного).

Xочется посоветовать

  • заюзать любой messaging framework с которым вы а) знакомы б) доверяете его производительности и надежности г) уверены что он проживет 10-20лет (или вы сможете его поддерживать сами)
  • слать через него xml-сообщения или бинарные с оговоренным форматом (или количество и вид этих форматов должен быть как-то декларативно описан)
  • стараться смотреть в сторону open source, не читать буклеты Oracle & Microsoft
  • в итоге вы получите 20% функционала biztalk который покроет 80% хотелок, остальное можно дописать по ходу дела..


Утилиты для xml

Intellij IDEA , Intellij WebStorm , Eclipse – тут всё ясно, прозрачная валидация и автоподстановка имен элементов, редактирование XML.

XMLPAD – править, смотреть, считать XPATH, валидировать итп

Xml Notepad – смотреть 1Gb+ файлы

Notepad++ - есть достаточно хороший plugin xml tools для работы с XML

SOAP UI – для работы с веб-сервисами: вызов, генерация тестовых сервисов по wsdl, отладка, авто-тесты.

TcpTrace – прозрачный port редиректор\сниффер для просмотра TCP-трафика

Altova, Oxygen – крутые и навороченные XML IDE, в них можно делать практически всё, но необходимость в их использовании довольно сомнительна

четверг, 3 ноября 2011 г.

Java Logging: история кошмара

Вступление


Тернист и извилист путь Java-платформы к правильному способу записи строчек в лог-файлы. История logging в Java довольно познавательна в плане изучения особенностей Open Source, в том числе его взаимодействия с корпорациями и единичными программистами. Я собираюсь рассказать столько, сколько возможно, об истории развития Java logging, а также о том, к чему все пришло и как жить дальше. Мой анализ ситуации будет довольно субъективен про причине того, что logging — это всегда дело вкуса, а вкусы у меня сформировались свои, взрослые. Я думаю, что это будет познавательно не сколько в плане каких-то технических особенностей всего зоопарка logging frameworks, а в плане политики и психологии разработчиков в модели Open Source.

Начало


Понятно, что любая logging-библиотека должна позволять как минимум печатать строку на консоль/в лог-файл.

В начале был, конечно System.err.println. Кроме того, первая версия Servlet API имела в составе функцию log (впрочем, довольно примитивную).

Одним из вариантов более продвинутых решений в 1999 году был проект Avalon (и подпроекты, которые назывались Excalibur и Fortress), который помимо сервисов DI предлагал интерфейс LogEnabled. В компонент, который объявлял себя LogEnabled, инжектировался (я применяю это слово вместо «инъектировался», чтобы подчеркнуть его связь с DI) объект типа Logger, куда можно было писать: а) строки б) exceptions. Подход этот по тем временам казался свежим и новаторским, однако с современной точки зрения это чистой воды идиотизм и over-engineering. Использовать DI для логгирования никакого смысла нет, и статический экземпляр этого самого Logger вполне бы всех устроил. В Avalon же приходилось думать, куда этот проклятый Logger сохранить и что же делать, если класс не использует DI (т.е. не управляется контейнером), а логгировать в нем очень хочется.

Приблизительно в 1999 появляется библиотека нового поколения — log4j. Прототип библиотеки был разработан IBM (еще в эпоху, когда голубой гигант пытался втиснуть Java в OS/2), затем эстафету подхватил ASF. Продукт был уже гораздо более продуманный и обкатанный на реальных нуждах. Вообще надо сказать, что серверным приложениям на Java к тому моменту исполнилось всего где-то годик, а логгирование всегда было востребовано именно на сервере. За это время Java-сообщество начало постепенно понимать, что и как им нужно.




log4j разделил понятие логгера или категории (т.е. область приложения, которая хочет записать в лог), собственно записи в лог, которую осуществляют так называемые appenders, и форматирования записей (layout). Конфигурация log4j определяет, какие appenders к каким категориям прикрепляются и сообщения какого уровня (log level) попадают в каждый appender.

Краеугольный камень log4j — это иерархичность категорий. Например, можно логгировать все сообщения из org.hibernate и заглушить всё из org.hibernate.type. Через некоторое время де-факто установилась практика соответствия иерахии категорий и иерархии пакетов в приложении.

Иерархия категорий позволяет довольно эффективно отсекать лишние сообщения, поэтому log4j работал чрезвычайно шустро. Кстати, принципиальной для логгеров является не столько скорость записи, сколько скорость фильтрации ненужного (а ненужного обычно более 90%) и форматирование.

Принципы, заложенные в log4j, были довольно удачно портированы на другие языки: log4cxx, log4net (и свежий детеныш — log4php). Стандартный пакет logging в Python 2.x представляет собой переработанный log4j (с небольшой добавкой других библиотек).

Итак, резюмируем. Удачная архитектура, понятная схема конфигурирования, принцип fail-safe — почему бы не включить такую замечательную библиотеку в состав платформы?

Java Logging API


На деле все получилось странно. IBM, в недрах которой возник log4j, оказалась довольно шустрой в вопросах формирования нового JSR47 (Java Logging API). В частности, ответственный за JSR47 товарищ Graham Hamilton решил взять за основу не log4j, а оригинальный IBM logging toolkit. Причем logging toolkit был использован на полную катушку: совпадали не только имена всех основных классов, но и их реализации; код старались допиливать как можно меньше, видимо, чтобы успеть к очередному релизу платформы. Впрочем, концептуально это было очень похоже на log4j, только вместо appenders это называлось handlers, а вместо layout был formatter.

Поскольку основное назначение JSR47 — определять API, а не реализацию, доступных (по умолчанию в платформе) средств вывода было всего 4 (в log4j более 10), а средства форматирования были настолько бедны, что практически сразу приходилось делать свои formatter-ы, поскольку готовых не хватало. JSR47 предлагал использовать конфигурацию в виде .properties, причем в скобках отмечалось, что в файле можно описать не все. Таким образом, при усложнении конфигурации программист неожиданно обнаруживал, что опять требуется писать код, т.к. в виде .properties его конфигурация нереализуема.

Нельзя сказать, чтобы JSR47 проигрывал в производительности. Местами он обгонял log4j за счет поддержания в памяти специального представления своей конфигурации (что, кстати, одновременно усложняло эту самую конфигурацию). Однако, как выяснилось, JSR47 в обязательном порядке собирал так называемую Caller Information, то бишь «откуда логгируется данное сообщение». Получение Caller Information — операция довольно дорогостоящая, протекает она с использованием Native-кода. Опытные дяди из log4j это знали, поэтому предоставляли эту возможность с оговоркой «лучше не включайте».

Разработчики log4j выступили с открытой петицией, где потребовали «снять JSR47 с конвейера», пока он еще не попал в состав платформы. Петицию подписали более 100 человек… Однако было уже поздно. Следующий релиз JDK был утвержден и платформа понеслась в будущее с рудиментарным java.util.logging, или сокращенно JUL. Новый логгинг был настолько неразвит и неудобен, что использовать его решились только в нескольких серверах приложений (среди них Resin и Jetty). Sun, впрочем, отреагировала на петицию и большинство крупных проблем оригинального JSR47 постепенно были устранены. Тем не менее, эти манипуляции походили скорее на установку подпорок к деревянному мосту, которые ну никак не сделают этот мост железобетонным. Разработчики log4j сделали реверанс в сторону Sun, заметив, однако, что степень кривизны JUL все еще довольно высока. Помимо всего прочего, лицензия JDK 1.4 не позволяла использовать log4j в качестве реализации JUL. Последний поезд для log4j ушел.

Не будучи способным поддержать большое число лог-писателей (т.е. handlers), JUL выпендрился, определив неимоверное число уровней логгирования. Например, для отладочных сообщений существовало аж 3 уровня — FINE, FINER и FINEST. Видя всё это, разработчики зачастую совершенно не понимали, какой же из трех уровней, чёрт возьми, надо использовать.

Java-сообщество было совершенно дезориентировано появлением «стандартного» логгинга параллельно с популярным, стабильным и развивающимся log4j. Никто не понимал, кто из них двоих жилец. Нередки были ситуации, когда в проекте было собрано несколько библиотек, каждая из которых использовала свой логгинг и свои настройки, записывая совершенно вразнобой свои лог-файлы.

Разумеется, сообщество попыталось исправить эту проблему. Началась оберточная эпидемия. Или, я бы даже сказал, пандемия.

Wrapper Hell


Когда вы подключаете несколько библиотек и пытаетесь соединить их логи в одно целое (а код модифицировать нельзя), это будет называться Adapter. Были написаны переходники из JUL в log4j и наоборот. К сожалению, переходники по функционалу являются «наименьшим общим кратным». Даже когда в log4j появилась поддержка контекста (NDC и MDC), при переливании в JUL она терялась. Хуже того, JUL работал только начиная с JDK 1.4, в то время как неимоверное количество enterprise-приложений все еще сидело на 1.3. В итоге, сообщество стало одержимо идеей создания «общего стандарта де-факто», который бы все стали дружно употреблять и который работал всегда и везде.

Приблизительно в 2002 из группы Jakarta выделился проект под названием commons-logging (JCL = Jakarta Commons Logging). Фактически это была обертка всех существующих на тот момент средств логгинга. Предлагалось писать приложения так, что они обращались к обертке (интерфейсу под названием Log), которая выбирала «подходящую» систему логгинга и сама к ней подключалась. Обертка была бедновата фунционально и никаких дополнений к существующим средствам логгинга не вносила.

Как же автоматически выбиралась подходящая система логгирования? А вот это самое интересное. Во-первых, можно было задать ее явным образом размещением специального commons-logging.properties-файла где-нибудь в CLASSPATH. Во-вторых, через системное свойство (что, очевидно, никто делать не будет). В-третьих, если где-то в CLASSPATH обнаруживался log4j, то он автоматически задействовался. Таким же методом разыскивались реализации всех остальных библиотек, всегда подключалась первая найденная.

Красиво! Ну то есть было бы красиво, если бы весь софт в мире использовал бы commons-logging. Тогда можно было спокойно собрать JARы, положить в сервер приложений, а там уж JCL подхватит логгинг данного сервера приложений и вуаля!

На самом деле, как выяснилось, куча софта использует обычно «любимый логгинг своего разработчика». Это означает, что совершенно произвольная библиотека может в виде зависимости подтянуть, например, log4j, который таким образом попадет в CLASSPATH и неожиданно переключит JCL на использование log4j. Еще хуже с commons-logging.properties. Если какой-нибудь деятель додумывался запихнуть его в свой JAR, то при подключении этого JAR-а — сами понимаете — пиши пропало. Особую пикантность ситуации придавало то, что совершенно непонятно было, из какого именно JAR-а приехала инфекция. Иногда помогал перебор всех JAR-ов в алфавитном порядке. Иногда бубен.

Полная непредсказуемость выбора логгинга оказалась главной и очень веселой особенностью JCL. Группа log4j разразилась гневной статьей Think again before adopting the commons-logging API, где предлагала остановить эпидемию и сосредоточить внимание на доработке существующего решения — log4j.

К сожалению, было уже поздно. С подачи Jakarta на commons-logging были переведены сотни, а затем тысячи библиотек. В их числе были Hibernate, Spring, Tomcat. После чего многочисленных пользователей этих библиотек захлестнула волна проблем, в целом описываемых как ClassLoader hell. В серверах приложений используется довольно сложная иерархия ClassLoader-ов, причем зачастую с серьезными отклонениями от стандарта J2EE. В этих условиях иногда JCL инициализируется дважды, причем неправильно, приводя к совершенно мистическим stack traces, не позволяющим даже заподозрить, что проблема в лог-обертке.

Почему, собственно говоря, Open Source сработал таким странным образом, породив на свет данное извращение? Почему разработчики не решились просто так взять и использовать другой зрелый и популярный Open Source продукт — log4j? Дело здесь, возможно, в некоторой инертности сообщества, привыкшего идти на поводу либо у ASF (а группа Jakarta, породившая данный кошмар, есть часть ASF), либо у Sun. Как только образуется критическая масса проектов, использующих JCL, все остальные (и не самые глупые люди, так ведь, Gavin King?) начинают использовать JCL (ибо Apache — это круто!). Это в целом напоминает броуновское движение, где такие бренды как Apache или Sun способны создавать области низкого давления, куда устремляются миллионы разработчиков. В случае JCL «история успеха» описана в блоге Rod Waldhoff (один из разработчиков так называемых Jakarta Commons) в 2003 году.

Новый виток прогресса


Итак, где-то на 2004 год имеем в комплекте:
  1. Стабильный и функционально развитый log4j
  2. Унылый java.util.logging
  3. Проблемный commons-logging
  4. Несколько мелких логгеров, недостойных упоминания

Отметим, что в проекте log4j в это время преобладали консервативные настроения. Особое внимание уделялось вопросу совместимости со старыми JDK. Вроде бы начинается разработка новой ветки log4j — 1.3.x. Эта версия — своего рода компромиссное решение: да, хочется новый функционал, да, хочется поддерживать обратную совместимость, да, попробуем угодить и нашим и вашим. А тем временем на подходе JDK 1.5 с varargs, JMX extensions и кучей других подарков. В команде log4j началось брожение умов. Отпочковывается ветка 2.x — несовместимая с основной веткой 1.2.x и созданная специально для JDK 1.5. Java-сообщество изнывает в нетерпении. Происходит вроде бы как что-то. Но что именно, не понять — log4j 2.0 по-прежнему остается недостижимой альфой, log4j 1.3 дико глюкав и не обеспечивает обещанной drop-in совместимости. И только ветка 1.2 по-прежнему стабильна и жива-здорова, прыгнув за несколько лет — внимание! — с версии 1.2.6 до 1.2.12.

Где-то в 2006 году один из отцов-основателей log4j — Ceki Gülcü — решает выйти из стремительно тухнущей команды. Так появляется на свет очередная «обертка всего» под названием SLF4J (Simple Logging Facade for Java). Теперь это обертка вокруг: log4j, JUL, commons-logging и нового логгера под названием logback. Как видно, прогресс быстро дошел до стадии «обертка вокруг обертки». Нетрудно спрогнозировать, что по той же схеме число обертываемых библиотек будет расти как факториал. Однако SLF4J предлагает и другие прочие выверты. Это специальные binary-переходники: из log4j в SLF4J, из commons-logging в SLF4J и тому подобное. Делаются такие переходники для кода, исходники которого недоступны; при этом они должны подменить оригинальные JAR-ы лог-библиотек. Не берусь представить себе, какая каша при этом образуется, но если очень хочется, то можно и так.

При всей моей ненависти к оберткам, положа руку на сердце, SLF4J — хорошо сделанный продукт. Были учтены все недостатки предшественников. Например, вместо шаманских плясок с поиском классов в CLASSPATH придумана более надежная схема. Теперь вся обертка делится на две части — API (который используется приложениями) и Реализация, которая представлена отдельными JAR-файлами для каждого вида логгирования (например, slf4j-log4j12.jar, slf4j-jdk14.jar и т.д.). Теперь достаточно только подключить к проекту нужный файл Реализации, после чего — опа! весь код проекта и все используемые библиотеки (при условии, что они обращаются к SLF4J API) будут логгировать в нужном направлении.

Функционально SLF4J поддерживал все современные навороты типа NDC и MDC. Помимо собственно обертывания вызовов, SLF4J предлагал небольшой, но полезный бонус при форматировании строк. Бонус тут в следующем. В коде часто приходится печатать конструкции вида:
Помимо собственно печати строки, тут неявно произойдет преобразование user.toString() с последующей конкатенацией строк. Все бы ничего. В отладочном режиме скорость выполнения нас не очень волнует. Однако даже если мы выставим уровень, скажем, в INFO, окажется, что конструирование строки все равно будет происходить! Никаких чудес: строка конструируется перед вызовом log.debug, поэтому log4j не имеет возможности как-то это контролировать. Если представить, что этот log.debug размещен в каком-то критическом внутреннем цикле… в общем, так жить нельзя. Разработчики log4j предложили обрамлять отладочный код так:
Нехорошо получается. По идее все эти проблемы должна брать на себя сама logging-библиотека. Эта проблема стала просто ахиллесовой пятой log4j. Разработчики вяло реагировали на пинки, рассказывая, что в logging-вызовы теперь можно еще добавить объект (ровно один!), да еще описать, как этот объект будет записан в лог с помощью интерфейса ObjectRenderer. По большому счету, все это были отмазки и полумеры.

SLF4J не был стиснут рамками совместимости со старыми версиями JDK и API, поэтому с ходу предложил более изящное решение:
В общем-то, все просто. В данной строке {} — это ссылки на параметры, которые передаются отдельно. Преобразование параметров в строку и окончательное форматирование лог-записи происходит только при установленном уровне DEBUG. Параметров можно передавать много. Работает! Не надо писать обрамляющий if и прочую тупость!

В скобках надо отметить, что данную возможность также совершенно неожиданно реализовал язык Groovy, где есть понятие GString, т.е. строка вида , которая неявно связана с несколькими контекстными переменными (здесь это user, request), причем вычисление строки происходит отложенным образом. Это очень удобно для таких лог-библиотек как log4j — можно получить на вход GString, а затем или выбросить его без вычисления, или все-таки преобразовать в нормальную (статическую) строку — String.

Короче говоря, SLF4J был сделан грамотно, с заделом на будущее. Это вызвало серьезный рост его популярности среди сообщества: сейчас SLF4J используют такие значимые проекты, как Jetty, Hibernate, Mina, Geronimo, Mule, Wicket, Nexus… в общем, практически все неудачники, зависшие в свое время на commons-logging, перешли на SLF4J. Интересно, что мешало усовершенствовать commons-logging до нужного состояния много лет назад? Но таковы реалии Open Source — развитие софта в нем происходит скорее революционно, чем эволюционно.

Одновременно с SLF4J был подан к столу совершенно новый логгер — Logback. Он был сделан человеком, который на логгировании собаку съел, и на поверку действительно оказался хорошим продуктом. Logback был изначально заточен под JDK 1.5+, одним махом избавившись от всех старческих болезней обратной совместимости, свойственных проекту log4j. А это значит — varargs, java.util.concurrent и прочие прелести. Например, за счет встроенной системы runtime-фильтрации можно менять уровень логгирования в зависимости от пользовательской сессии, разбрасывать пользователей по разным лог-файлам и прочее, прочее.

Я подкину горчички в идиллию, нарисованную автором. Большинство этих возможностей можно реализовать в виде дополнительных appender-ов к log4j. Придется искривить и подпилить конфигурацию, это сложнее, но — факт, что переходить для этого на новый логгер не_обязательно. Таким образом, все рекламируемые Logback фишки — удобные, но не уникальные.

Что касается сообщества, то оно к Logback относится с осторожностью. Во-первых, за несколько лет он добрался до версии 0.9.x, а это пугает некоторых программеров. Во-вторых, Logback не находится ни под зонтиком Apache, ни в области действия Sun. Это смущает людей щепетильных. В-третьих, автору надо кушать, поэтому за некоторые довески к Logback и поддержку он требует денег. Это иногда отпугивает студентов. Помимо всего прочего, Logback имеет довольно сложную двойную лицензию (LGPL/EPL), в то время как log4j — универсальную лицензию Apache. Для библиотек и вообще redistributable софта лицензирование является очень тонким моментом.

По большому счету, Logback на сегодняшний день — вершина эволюции. Помимо Logback появилось уже с десяток новых logging-библиотек, но с большой вероятностью ни одна из них не выживет. Подводя итоги, ситуация на данный момент следующая:
  • log4j — используют подсевшие на него изначально и не видящие необходимости перехода.
  • JUL — тихо умирающий стандарт. Все, кто изначально пытался его использовать, переезжают на Logback.
  • commons-logging — обычно задействован в legacy-библиотеках, которые очень боятся причинить неудобства пользователем, переехав на что-нибудь получше.
  • SLF4J — очень популярен в библиотеках. Многие переехали на него, не выдержав ужасов commons-logging
  • Logback — обычно современные high-performance серверы, которых не устраивает log4j.

Я уже говорил, что Open Source сообщество имеет тенденцию стекаться к «центрам тяжести». Сейчас таким центром тяжести выступает скорее SLF4J в силу «универсальности». Относительная популярность SLF4J в какой-то степени гарантирует от появления новых оберток. Число проектов, использующих SLF4J, уже является достаточным для накопления «критической массы». У Logback (того же автора, заметьте) такой критической массы нет. (Кстати, log4j по прежнему обещает нам золотые горы и версию 2.0, однако воз и ныне там.) Думаю, если Logback усмирит свою гордыню и двинется в Apache, его позиции сильно улучшатся.

Заключение


Интересно посмотреть на историю вопроса под углом психологии программистов. Ведь в принципе всё это спиральное (и вроде как прогрессирующее!) движение — бесконечный «reinvent the wheel». То есть из двух вариантов «доработать существующее» и «сделать свое» всегда выбирался второй. Поэтому ни один из упомянутых проектов не выбился в безусловные лидеры (в те самые стандарты «де-факто»). Вместо этого разработчики были в разное время «нашинкованы» на разные проекты и действовали раздельно, вместо того, чтобы действовать сообща. Хотя не факт, что все авторы смогли бы работать в одной упряжке. Тут действовали и политические моменты (вспомним, как Graham Hamilton любил IBM), и просто банальные ссоры в команде. Стремление же участников Jakarta Commons обеспечить сообществу «свободу выбора» вообще обернулось для сообщества длительной «эпидемией оберток».

В общем-то, все эти пороки типичны для открытого сообщества. Эта более чем 10-летняя история также показывает, насколько ошибочно распространенное сейчас мнение, что Sun как будто бы что-то решало в Java-сообществе. Мы видим, что многие вещи происходили вопреки Sun и независимо от Sun. Одним словом, интересно, как оно пойдет дальше. В одном я уверен — проекты приходят и уходят, люди не меняются :)



Заметка взята с Хабра чтобы не пропала, со всем этим сталкивался не раз и согласен с автором на 100% ..

Книжки по теме




The Complete Log4j Manual: The Reliable, Fast and Flexible Logging Framework for Java

вторник, 18 октября 2011 г.

Как я сдавал Oracle/Sun Certified Java Programmer 6 (SCJP)




Сдавал в конце июля, к тому моменту Oracle перевел сертификацию с Prometric центров на PersonVue и поменял вопросы.

Общая информация по экзамену есть на сайте Oracle

От SCJP5 отличия минимальны:
  • сертификация стала немного более жесткой, для получения SCJP необходимо дать правильные ответы на 65% вопросов (вместо 59%). Но дается существенно больше времени: 210 минут вместо 175.
  • добавлены задачи на Console, String.format итп.
  • добавлены вопросы по интерфейсам NavigableSet и NavigableMap.
  • убрали вопросы, касающиееся переопределения методов и конструктора
  • убрали вопросы где надо было писать код с помощь drag-n-drop метода




Как сдавать:
  • Качаем книжки и тесты c rutracker'a.
  • Качаем Whizlabs Suite for SCJP 6 c пиратской бухты
  • Читаем Catty Sierra для SCJP 6 хотя бы на 30-40% ,стараемся запомнить
    • какие типы вопросов бывают
    • какое API от нас требуют запомнить
    • на это может уйти неделя и больше, книжка порядка 1К страниц

  • Проходим Whizlabs тест раза 3-4

    это долго и нудно.. каждый тест - несколько часов;

    по результатм теста желательно найти все ошибки и понять чем они вызваны.. мои категории были такие
    • невнимательность (поторопился, устал, поленился разобраться итп)
    • не знал дурацкое api (мелочи которые требуется помнить вида какой параметр где и как идет)
    • не знал как это вообще работает
    • не успел пройти ( и такое бывает.. важно успевать решать каждый вопрос в среднем за 2-3 минуты)


    По результатам если что не знаем то 2+3 исправляется чтением гугла и Catty Sierra.

  • Региструемся на Personvue

    в недрах сайта выбираем экзамен Oracle/1Z0-851
    выбираем где сдавать + время и место (стоит порядка 150$).

    Сразу после оплаты в личном кабинете дается 2! бесплатных теста полностью аналогичных реальному тестированию.

    Разбор полетов после их сдачи дает гораздо больше чем все предущие тесты в Whizlabs.
  • Пойти и сдать.. я набрал 95% :)

четверг, 13 октября 2011 г.

Собеседование по Java concurrency



Нашел интересный список из over 50 вопросов к интервью по Java concurrency и многопоточности. На все старался отвечать честно, что совсем не знал - гугл (~11 вопросов в основном на тему хитрых названий).

Ниже то что получилось.


Назовите различия между Collections.synchronizedMap(new HashMap()) и ConcurrentHashMap.
SynchronizedMap оборачивает обычный Map используя единственный монитор для блокировки,
тогда как ConcurrentHashMap
  • позволяет делать неблокирующее чтение (но можно увидеть старые\невалидные данные)
  • на запись делит map на секции, к каждой из которых идет свой объект блокировки (это уменьшает общее время ожидания)
Что такое кооперативная многозадачность и есть ли она в Java. Если да, то какие преимущества. Если нет, то какая тогда в Java?
Способ деление времени CPU между потоками при котором каждый поток обязан отдавать управление следующему добровольно.

Преимущества - возможно меньшие накладные расходы на переключение контекста если среда исполнения полностью нами контролируется (нет лишних переключений контекста)

Недостатки - если один поток завис или ведет себя некорректно то вся система зависла и другие потоки никогда не получат управление.

В Java - вытесняющая многопоточность.
Что такое "зеленый потоки" и есть ли они в Java (в HotSpot JVM.6)?
Легковесные потоки (эмулируемые) виртуальной машиной или средой исполнения..

не подрузамевают под собой реального создания соотв. потоков ОС, как следсвие нет переключения между USER и KERNEL режимами ядра ос. В Java6 нету.
Различия в интерфейсах Runnable и Callable.
первый не может вернуть результат или бросить Exception, оба - обертки кода для вызова из других потоков
Напишите минимальный неблокирующий стек (всего два метода — push() и pop()).
Напишите минимальный copy-on-write ArrayList (всего четыре метода — void add(int indx, int item), int get(int indx), void remove(int indx), int size()).
Различя между Thread.isInterrupded() и Thread.interrupted().
interrupted() проверяет флаг того что поток прерван и сбрасывает его, isInterrupded() ничего не трогает и можно вызывать несколько раз
Что происходит при вызове Thread.interrupt()?
Если поток
  • заблокирован на мониторе, ждет другой поток итп (wait, notify) - вылетит InterruptedException но флаг interrupted потока не поставится
  • Если поток ждет ввод-вывод на InterruptableChannel то тоже вылетит exception
  • Ecли поток ждет ввод-вывод то он тут же прекратится и выставится флаг Interrupted
  • Либо просто ставится статус Interrupted
Некоторые из следующих методов deprecated а некоторые и не были никогда реализованы. Какие? Thread.interrupt(), Thread.stop(), Thread.yield(), Thread.suspend(), Thread.resume(), Thread.join(), Thread.start(), Thread.run(), Thread.sleep().
  • stop(), suspend(), resume() - deprecated т.к. могут убить\остановить поток оставив его ресурсы в неизвестном\промежуточном состоянии которое не является валидным
  • interrupt() - прерывает поток если он занимается I/O и выставляет флаг interrupted
  • yield() - принудительно передает квант времени следующему потоку
  • join() - текущий поток ждет другой поток
  • start() - стартует нитку
  • run() - стартует код в текущей нитке без порождения отдельного потока
  • sleep() - усыпить поток на некоторое время, не отпуская захваченные локи\мониторы\ресурсы
Что Вы знаете о асинхронных вызовов методов? Есть ли это в самом языке Java? Если есть, то как реализовано? Если нет, то как бы Вы реализовали?
Есть ExecutorService который принимает Callable, и возвращает интерфейс Future; это позволяет
  • заблокироваться и подождать завершения вычислений
  • следить за тем выполнен Callable или нет
  • отменить вычисление если оно не закончислось
Перечислите ВСЕ причины по которым может выскочить InterruptedException.
Поток ждет в wait, sleep(...), join() или заблокирован на длительное время аналогичным вызовом.. и из соседнего потока дернули interrupt()
Что изменилось между JMM до Java 5 и NewJMM после Java 5?
volatile дает более внятные happens before гарантии, не только на порядок присвоения самих volatile переменных но и на side-эффекты. Плюс стало возможным писать код вида и быть уверенным что в момент когда из другого потока обратятся к полю obj, ссылка будет присвоена уже проинициализированному объекту и конструктор полностью отработает. В старой Memory model ссылка могла присвоиться не полностью собранному объекту из за эффекта переупорядочивания инструкции VM и CPU.
В классе String все поля финальные. Можно ли убрать ключевое слово финал? Ведь сеттеров все равно нет — следовательно поля нельзя переустановить.
Нет, т.к. final поля нужны для безопасной "публикации" объектов между потоками.
Что такое ordering, visibility, atomicity, happens-before, mutual exclusion. И показать на примерах volatile, AtomicInteger, synchronize{} — что из вышеперечисленного списка присутствует и при каких вариантах использования.
  • ordering - определяет когда один поток может увидеть out-of-order (т.е. неправильный) порядок исполнения инструкций другого потока. CPU может переупорядочивать и выполнять x86 инструкции в произвольном порядке для повышения пифоманса до тех пор пока для потока внутри не видно никаких отличий. Называется такая гарантия as-if-serial semantics. Проблемы же появляются когда нужно получать доступ из нескольких потоков к общей памяти - все эти side-эффекты вылезают. Решается с помощью механизмов публикации\синхронизации\гарантий Java Memory Model
  • visibility - определяет когда действия в одном потоке станут видны в другом потоке
  • atomicity - атомарность операций, операция выглядит как единая и неделимая операция которая либо выполнилась либо еще нет
  • Как правило все ошибки в многопоточном приложении попадают из за несоблюдения одного из 3х - visibility, atomicity, ordering
  • happens-before - логическое ограничение на порядок выполнения программы, термин используется в спеке по Java Memory Model. Например если мы говорим что запись в переменную A и последующее ее чтение связаны чз эту зависимость - то как бы не переупорядочивались инструкции в момент чтения мы должны видеть все size-эффекты от выполненной ранее операции записи.
  • volatile - дает гарантии happens-before на все присвоения переменных до текущего момента (так называемый read memory barrier)/li>
  • AtomicInteger - позволяет выполнять атомарные Compare-and-swap операции реализованные аппаратно в CPU. Основная выгода от CAS операций появляется только при условии что переключать контекст процессора с потока на поток менее выгодно чем немного покрутиться в цикле while пытаясь выполнить апдейт вида boolean compareAndSwap(oldValue, newValue). Если время потраченное в таком цикле превышает 1 квант потока то atomic переменные может быть невыгодно использовать с точки зрения производительности..
  • synchronize - создает mutex (взаимоисключающую блокировку) некоторого объекта, каждый поток которые не может захватить объект блокируется на неопределенное время. mutex - частный случай semaphore с единственным состоянием.
Назовите отличия synchronize{} и ReentrantLock.
  • synchronize - более примитивная конструкция которая обязывает нас отпустить monitor по окончании секции. Таким образом захват\освобождение всегда идут парами и всегда связаны с некоторым блоком кода
  • ReentrantLock - можно захватывать и освобождать мониторы в произвольном порядке, дает гибкость но сложнее сделать все правильно. Также есть опция fair - следить ли за "честным" порядком предоставления доступа\времени ожидания потоков на мониторе.
  • ReentrantLock - лучше масштабируется при росте числа потоков
Что из данных вызовов создает happend-before: Thread.sleep(), Thread.join(), Thread.yield(), Thread.start(), Thread.run(), Thread.isAlive(), Thread.getState()?
Только join(), start(), isAlive()
Перечислите известные Вам способы борьбы с priority inversion, назовите классы систем где они особенно опасны.
Опасны в real time системах, возникают из за особенностей планировщиков задач\прерываний. Способов предотвращения несколько -
  • отказ от прерываний на время выполнения критичного высокоприоритетного кода
  • временный подьем приоритета до максимального у каждой задачи которая захватила ресурс, чтобы предотвратить задвигание высокоприоритетных заблокированных на ресурсе задач в очереди ожидания низкоприоритетными и незаблокированными
Перечислите известные Вам способы 1)избежать 2)побороть возникшие deadlock-и (представьте, что вы пишете ядро RDBMS).
Чтобы избежать дедлоков -
  • Захватывать везде ресурсы в одинаковом порядке
  • или знать заранее какие ресурсы в каком порядке будут захвачены - строить граф переходов м-ду состояниями
Чтобы побороть дедлок
  • использовать тул для детекта заблокированных потоков
  • использовать эвристику вида - убивать один из двух потоков если оба взаимно блокируют друг друга. например можно поделить потоки на молодые и старые. более молодые потоки можно убивать при обнаружении что он пытается захватить ресурс используемый более старым потоком.
Расскажите о паттернах Reactor/Proactor?
Оба паттерна используются для высокопроизводительной обработки данных и разделения потока данных по worker-потокам. Основное отличие в том вычитывает ли listener сам данные или ждет пока это сделает callback, во многом на производительность и предпочтительный шаблон влияет наличие в ОС асинхронного ввода вывода и насколько хорошо он реализован. В Win - выигрывает Proactor, в *nix - Reactor.
  • Reactor - получил нотификацию что данные пришли, уведомил user callback, callback сам вычитал нужные данные, callback их обрабатывает
  • Proactor - полчил нотификацию что данные пришли, сам вычитал нужные данные в буфер, уведомил user callback чтобы тот забрал данные, callback их обрабатывает
Что такое "monitor"?
Объект для синхронизации. Используется для безопасного разделения ресурсов между потоками (Mutex).
Что такое "private mutex"?
Объект для синхронизации делается private, чтобы сторонний код не мог на него синхронизироваться и вдруг случайно получить deadlock.
Что такое "priority inheritance"?
Повышение приоритета текущей задачи которая захватила ресурс до максимально возможного.. чтобы избежать неправильного планирования других задач которые находятся в ожидании ресурса
Что такое "backoff protocol (exponential backoff)"?
Некоторая договоренность (алгоритм) между потоками (или нодами) что делать в случае конфликта. Например после неудачной попытки захватить ресурс интервал повторной попытки на каждом ноде должен вычисляться так чтобы минимизировать вероятность повторного конфликта\совпадения по времени с другими нодами.
Что такое "task stealing"?
Если очередь задач для потока исчерпана, поток может брать задачи у соседних потоков из очереди, выбирая , например, по времени их добавления.
Что такое "ABA problem"?
Возникает при compare-and-swap вызовах если значение переменной переполнилось (или совершило цикл\вернулось к старому значению). В этом случае механизм compare-and-swap перестает быть надежным.
Что такое "test-and-set"?
Аналогично compare-and-swap но при сравнении значение проверяется на 0.
Что такое "test-and-test-and-set"?
Перед использованием test-and-set стараемся предварительно проверить занят ли лок кем либо другим (например выполняем цикл пока некоторая shared-переменная не покажет что ресурс свободен)
Что такое "spin lock"?
Поток ждет освобождения lock'a проверяя в цикле условие\ресурс.
Что такое "sequential consistency"?
То же что и as-if-serial semantics, гарантии что в рамках одного потока побочные эффекты от всех операций будут такие, как будто все операции выполняются последовательно.
Что такое "sense-reversing barrier"?
Способ повторного использования для Barrier. В барьере хранится флаг sence, и в каждом потоке его использующем хранится аналогичный флаг в ThreadLocal переменной. Идея в том чтобы меняя эти флаги при вызове await() использовать барьер для поочередной разблокировки то одного потока то другого.
Что такое "safe publication"?
Показ объектов другим потокам из текущего, не нарушая ограничений visibility. Способы публикации в Java:
  • static{} инициализатор
  • volatile переменные
  • atomic переменные
  • сохранение в shared переменной, корректно защищенной с использованием synchronized()или Lock'и и другие конструкции создающие read/write memory barrier
  • final переменные в shared-объекте который был корректно проинициализирован
Что это за свойство — "reentrancy"?
Возможен повторный захват монитора, владельцем которого текущий поток уже является. Сильно упрощает код и позволяет делать рекурсивные вызовы, легче избежать deadlock'a.
Что такое "recursive parallelism"?
Разбиение задачи на подзадачи по методу разделяй-и-властвуй (divide-and-conqueer). Каждая задача решается в отдельном потоке.
Что такое "iterative parallelism"?
Разбиение задачи на независимые итерации, каждая итерация может считаться независимо в своем потоке.
Что это за вариант архитектуры "pipeline"?
Общий процессинг разбивается на стадии, каждая стадия выполняется собственным узлом; узлы связываются в конвеер так чтобы выход предыдущего узла попадал на вход следующего. Примерно так работает выполнение команд во всех современных x86 процессорах.
Что такое "poison message"?
Сообщение в очереди, которое превысило максимально допустимый срок жизни\максимальное количество попыток на повторную посылку или обработку.
Что такое "mutual exclusion"? Примеры как добиться в Java.
Критическая секция, семафор с одним состоянием; простейший пример - synchronized(obj) { ... }
Что такое "condition waiting"? Примеры как добиться в Java.
Вообще это называется guarded lock. Если поток захватил монитор и позвал wait() на нем чтобы дождаться некоторого состояния, проверка наступления этого события должна быть завернута в цикл вида
Преимущества ScheduledThreadPool перед java.util.Timer.
  • Timer имеет только один фоновый поток для исполнения, т.е. если задач много или они долгие - поток не справляется, время запуска других задачек сдвигается
  • Timer может умереть из за неожиданного RuntimeException полученного на выходе любой из TimerTask'ов
  • Timer криво работает если меняется системное время, т.к. он использует object.wait() чтобы дожидаться следующего момента исполнения
  • ScheduledThreadPool использует System.nanotime() который глючит на старых OC (winxp) и сильно зависит от версии OS и CPU
Различия между java.util.concurrent.Atomic*.compareAndSwap() и java.util.concurrent.Atomic*.weakCompareAndSwap().
  • weak не создает memory barrier и не дает гарантии happens-before
  • weak сильно зависит от нижележащего кеша\CPU, и может возвращать false без видимых причин и делать это часто
  • weak, как следствие, более легкая операция, но поддерживаемая далеко не всеми архитектурами и не всегда эффективная
Что в SynchronousQueue уникально для BlockingQueue.
SynchronousQueue имеет нулевой размер, используется для обмена между потоками, реализация такова что сам метод обмена хитро блокирует потоки друг на друга используя busy wait подход и затем передает объект от источника к потребителю минуя любые внутренние переменные.
Что такое "рандеву"? При помощи каких классов в Java его можно организовать?
Способ собрать запущенные потоки в "одном месте". Можно использовать Barrier, Latch, spin lock..
Что такое "false sharing". Может ли происходит в Java. Если есть, то приведите примеры и как бороться. Если нет, то как побороли разработчики JVM.
Эффект который происходит если данные\переменные нескольких потоков попадают в один cache line процессора. В этом случае на многопроцессорной системе контроллеру кеша приходится делать много лишних действий чтобы каждый раз удостовериться что линии кеша на различных CPU не рассинхронизовались. Решить проблему вроде как можно изменив layout конечной памяти\добавив данных для padding'a. В JVM вроде никак не решено.
Thread.getState() возвращает экземпляр Thread.State. Какие возможны значения?
new, runnable, waiting, time_wait, terminated, blocked
Напишите простейший ограниченный буфер для многих производителей/многих потребителей с использованием synchronize{}. С использованием ReentrantLock.
вариант с synchronized()

вариант с ReentrantLock
Напишите реализацию класса с неблокирующим методом BigInteger next(), который возвращает элементы последовательности: [1, 2, 4, 8, 16, ...]. Код должен корректно работать в многопоточной среде.
У ReentrantLock созданного с аргументом true все же один из методов захвата блоктровки — не fair. Какой? Как это обойти?
tryLock(), использовать tryLock(long,TimeUnit)
Приведите наиболее существенное отличие между CountDownLatch и Barrier.
Barrier накапливает потоке в точке вызова await() пока их количество не превысит заданное. CountDownLatch ждет пока количество вызовов countDown() не превысит нужное, и тогда разблокирует await().
Что Вы знаете о Erlang? Что в нем есть существенного связанного с многопоточностью такого, чего нет в Java?
Функциональный язык программирования, с неизменяемыми переменными, легковесными потоками, заточенный на параллелизм и многопоточность. Все "потоки" общаются посредством посылки сообщений, разделяемые переменные\память отсутствуют как класс. Разработан для коммутаторов в Ericsson. Имеет внутреннюю встроенную базу, довольно быструю и устойчивую.
Что Вы знаете о CSP? Что в нем есть существенного связанного с многопоточностью такого, чего нет в Java?
Это язык для описания паттернов взаимодействия потоков исполнения в параллельных вычислениях. В CSP есть формальный мат аппарат для описания и проверки\доказательства непротиворечивости свойств задуманной "системы" параллельной разработки .
Отличие Thread.start() и Thread.run()?
start() порождает новый поток в котором исполняет код run().
Книжки по теме

The Art of Multiprocessor Programming

Java Concurrency in Practice

Pattern-Oriented Software Architecture Volume 2: Patterns for Concurrent and Networked Objects

The Little Book of Semaphores