пятница, 29 октября 2010 г.

Обновление максимального значения без использования блокировок

При реализации грамотных многопоточных механизмов, порой используют только синхронизованные блоки кода. Но, не следует также забывать и о функции CAS (Compare and swap, представленной соответствующей процессорной командой). Данная функция присутствует во всех классах пакета java.util.concurrent.atomic.

Алгортимы с использованием CAS являются безблокировочными, ведь потокам не приходится ожидать блокировок для их исполнения. Операция CAS выполняется успешно или неуспешно, но независимо от исхода она завершается в предсказуемые сроки. В случае неуспешности выполнения программа может сделать попытку выполнения этой функции, либо выполнить другие операции.

До недавнего времени примение CAS-у в своей практике я не находил. Однако, когда потребовалось реализовать многопоточный алгоритм обновления максимального значения, он оказался весьма уместен:

воскресенье, 8 августа 2010 г.

Реализация concurrent HashSet-а в Java

К сожалению, в JDK нет полноценной реализации concurrent HashSet-а, как в случае для HashMap - java.util.concurrent.ConcurrentHashMap. Есть CopyOnWriteArraySet, использующий внутри себя CopyOnWriteArrayList, но у него есть некоторые недостатки:

  • поиск элементов будет медленне ибо в List-ах он выполняется по equals, а не по hashcode -> equals.
  • невозможность удаления объектов при итерации (iterator.remove() - не реализован) и понятно почему, ведь при итерации используется копия коллекции.

Но выход есть, подобие ConcurrentHashSet можно сделать на основе ConcurrentHashMap, записывая как ключ элемент, а в значение какой-нибудь dummy-объект. Такая реализация представлена в виде org.jboss.util.collection.ConcurrentSet из бибилиотеки jboss-common-core.

вторник, 6 апреля 2010 г.

Транзакционные синхронизации в Spring Framework

Выполнение определенной логики по окончанию текущей транзакции в Spring Framework можно "подключать" динамически с помощью так называемых транзакционных синхронизаций.

Транзакционная синхронизация - это по сути callback-объект типа org.springframework.transaction.support.TransactionSynchronization, который содержит в себе определенные методы вызываемые из AbstractPlatformTransactionManager на соответствующие действия над транзакцией (afterCompletion, afterCommit, afterRollback, suspend и т.д.). org.springframework.transaction.support.TransactionSynchronizationManager - менеджер со статическими методами, используемый для регистрации и управления синхронизациями. При написании своей синхронизации в качестве базового класса удобно использовать org.springframework.transaction.support.TransactionSynchronizationAdapter. Вот пример:

суббота, 6 марта 2010 г.

Сериализация полей без set-методов и поддержка аннотаций в BlazeDS

Для передачи данных между BlazeDS 3.2 и клиентом рекомендуется использовать value object-ы. Эти объекты содержат только те данные, которые действительно необходимы клиенту.

К сожалению, в BlazeDS есть некоторые неудобства при сериализации объектов:

  • Обязательное наличие set-метода (можно и пустого), если вы хотите сериализовать поле у которого есть только get-метод

  • Сериализация enum-ов как объектов, вместо использования строчного значения, как заявлено в документации

Так же не очень удобно, на мой взгляд, является создание отдельных классов для каждого value object-a. Было бы удобнее помечать аннтоциями getter-ы или поля, которые будут учавствовать/отсутсвовать в value object-е, без создания нового класса.

Чтобы устранить вышеперечисленные недостатки придется разобраться с механизмом сериализации BlazeDS. Кратко опишу классы, которые задействованы при сериализации: flex.messaging.io.PropertyProxy - основной интерфейс, используемый для сериализации/десериализации объектов. Каждому классу объекта, передаваемому на клиента, соответствует определенная реализация PropertyProxy, в основном это flex.messaging.io.BeanProxy. Соответствие (Класс объекта - PropertyProxy-объект) держится в классе flex.messaging.io.PropertyProxyRegistry, при сериализации/десериализации BlazeDS получает PropertyProxy для какого-либо объекта используя методы: getProxy и getProxyAndRegister.

Т.к. PropertyProxyRegistry является singleton-ом, то замену реализации нам придется сделать через смену значения поля registry, которое спрятано внутри класса. Реализация, в которой убраны перечисленные выше недостатки, выглядит так:

вторник, 29 декабря 2009 г.

Запуск "Наемники : Карты судьбы"

Не так давно наступил день, который я так долго ждал. 25 декабря был запущен проект для ВКонтакте - игра "Наемники : Карты судьбы", над которым я трудился последние 2,5 месяца. Серверная часть проекта была реализована полностью мной, что называется "своими руками". Давненько мечтал о таком маленьком проекте, в котором я смогу применить все свои знания и опыт в области разработки.

Использовались следующие java-технологии:

  • Spring
  • Spring security
  • Spring BlazeDS Integration
  • BlazeDS
  • Hibernate
  • JBoss Cache
  • Unitils
  • Jmockit
  • DBUnit
  • TestNG

Думаю, что некоторые из вас скажут, что с использованием Hibernate хорошей производительности не добьешься, но я с этим не соглашусь. Да, в процессе разработки в Hibernate нашлись некоторые баги и выявилось весьма "необычное" поведение, но все эти проблемы можно решить.

Теперь, когда проект запущен, я могу снова начинать писать статьи, освещая некоторые проблемы с которыми я столкнулся при разработке.

Отмечу также и тот факт, что более 80% кода было покрыто тестами. Хотя этот процесс и занимал у меня до 50% времени, я считаю, что именно благодаря тестам удалось выйти в релиз с минимальным кол-вом багов на серверной стороне. Без тестов был бы невозможен безболезненный рефакторинг и быстрое добавление новой функциональности.

среда, 28 октября 2009 г.

Динамическая модификация контекста в Spring

Существует механизм изменения контекста Spring, который запускается после сбора всей информации о нем (из xml и аннотаций) и срабатывает до создания самих bean-ов. Я говорю об интерфейсе org.springframework.beans.factory.config.BeanFactoryPostProcessor, реализуя который вы получаете именно такую возможность. Используя данный механизм очень удобно менять параметры уже объявленных где-то в контексте bean-ов. Объект реализующий этот интерфейс можно зарегистрировать как обычный bean в контексте, либо добавить его на этапе создания контекста, например так:

Только не забудьте указать в конструкторе контекста аргументу refresh значение false, иначе наш механизм будет вызываться лишь для новых bean-ов добавляемых уж после создания контекста (как это делать я писал тут). При вызове метода refresh произойдет инициализация контекста и наш обработчик будет вызван.

Описанный выше прием оказывается очень полезен в использовании при тестировании, когда нужно изменить какие-то из параметров bean-ов или просто выставить свои значения.

понедельник, 17 августа 2009 г.

Управление версиями в Maven

После очередного релиза проекта приходится менять его версию, проходясь при этом по всем pom-файлам. Процедура эта довольно утомительная и избавить от нее поможет versions-maven-plugin.

Достаточно выставить в головном pom-файле новую версию проекта и затем выполнить команду:

mvn versions:update-child-modules

Как вы наверное догадались, команда выполнит обновление всех версий проекта в pom-файлах дочерних модулей. Если же, по какой-то причине, вы остались недовольны проделанной работой плагина, то содержимое pom-файлов можно легко вернуть в исходное состояние командой:

mvn versions:revert

Чтобы удалить backup-ы pom-файлов выполните:

mvn versions:commit

Помимо выполнения обновления версии проекта, есть еще несколько полезных возможностей. Вывод списка новых версий зависимостей проекта, доступных из репозитария:

mvn versions:display-dependency-updates

Список новых версий плагинов используемых в проекте:

mvn versions:display-plugin-updates