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

"Хорошая" новость от Oracle...

Хотя это событие было предсказуемо, после коммерциализации MySQL и OpenOffice, верить в него не хотелось. Похоже oracle хочет разделить версии JVM на "free" и "premium", подробнее тут.

среда, 3 ноября 2010 г.

Поиск по ключу входящему в числовой диапазон.

Дана таблица по которой, в зависимости от опыта игрока, определяется его уровень:

  Диапазон опыта     Уровень

0 < exp <= 12 1
12 < exp <= 30 2
30 < exp <= 67 3
... ...
231 < exp <= 300 10

Задача: реализовать алгоритм поиска уровня.

Для решения задачи я задействую класс java.util.TreeMap. Почему этот класс? Все просто, он реализует важный интерфейс - java.util.NavigableMap, появившийся с версии Java 1.6. Его метод

Map.Entry<K,V> ceilingEntry(K key)

как раз позволяет найти запись в map-е удовлетворяющую условию K(n) < key <= K(n+1) и при этом будет содержать значение по ключу K(n+1). Таким образом, остается составить map-у из записей: ключ - макс. значение опыта на уровне, значение - уровень. Код решения:

Для наглядности я захардкодил map-у в коде, на деле же она создается из xml.

пятница, 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, которое спрятано внутри класса. Реализация, в которой убраны перечисленные выше недостатки, выглядит так: