30 апреля 2010 г.

ReentrantLock и synchronized(lock)

Пока рылся в исходниках JetLang, наткнулся на такой класс, как RunnableBlockingQueue.java. Мне показалось интересным, что в нем используется ReentrantLock, хотя по функциональности вполне подойдет обычный synchronized() и wait()/notify() -- никакой новой функциональности из ReentrantLock не используется. Стало интересно, есть ли какой-либо эффект в плане производительности?

Взял, прямолинейно переписал RunnableBlockingQueue с использованием plain old synchronized style. Создал свой класс MyPoolFiber, использующий именно эту реализацию очереди, и сравнил производительность на примере пинг-понга.

С дефолтными настройками оба варианта неразличимы по производительности. А вот результат с -server меня удивил -- ReentrantLock весьма заметно быстрее. Примерно 7 к 6 в пользу ReentrantLock. Не ожидал -- мне казалось, что новое concurrency API более мощное, но и более медленное -- в тех случаях, когда используется теми же методами, что и старое.

JetLang

Игрался с библиотекой JetLang. Библиотека довольно компактная, и реализует идею message-based concurrency для джавы. Основной плюс идеи организации взаимодействия потоков через отправку-прием сообщений в том, что, при грамотной реализации, можно обеспечить очень низкий уровень столкновений блокировок (lock contention).

Вообще, я поначалу был несколько разочарован -- ожидал что-то вроде Scala Actors в миниатюре, пусть с ограничениями. Но JetLang это скорее бэкграунд, на фоне которого можно самому реализовать что-то вроде Акторов, если захочется.

С другой стороны плюс в том, что библиотека очень маленькая, и очень грамотно архитектурно реализована. Хотя некоторые концепции непривычны -- широкое использование Disposable, например, я с нетерпением жду оказии попробовать JetLang в каком-нибудь реальном проекте.

20 апреля 2010 г.

JFormattedTextField.selectAll

Нужно было сделать, чтобы JFormattedTextField выделял свое содержимое при получении фокуса. Стандартный addFocusListener -> .selectAll не сработал. Оказывается (см Sun bug #4740914) JFormattedTextField переопределяет processFocusEvent и внутри сначала зовет базовую реализацию (которая, в числе прочего, и FocusListener-ы оповещает), а потом переформатирует свое содержимое -- что, разумеется, все выделение напрочь убивает.

Решений нашлось два. Либо уныло-универсальное addFocusListener -> SwingUtilities.invokeLater -> selectAll, либо отнаследовать свой собственный класс от JFTF, и переопределить processFocusEvent, дописав в конец selectAll().

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

Вообще, в свинге очень много мест, где приходится использовать invokeLater без явной надобности -- просто потому, что черт ногу сломит разбираться с точной последовательностью обработки каких-либо событий.

4 апреля 2010 г.

Вышел jdk 1.6 под Snow Leopard

В последнем обновлении наконец-то появилась шестая джава под мак (SL).

Тут же появились и проблемы с ней. java.io.IOException: Keystore was tampered with, or password was incorrect -- вылетает при работе с SSL ссылка

Корень проблем оказался прост -- эппл сменила (скорее всего, просто по ошибке) дефолтный пароль на хранилище сертификатов с changeit на changeme. Если сменить его обратно -- все заработает как встарь. Например, вот так:

sudo -i
cd /System/Library/Frameworks/JavaVM.framework/Home/lib/security/
keytool -storepasswd -keystore cacerts

1 апреля 2010 г.

Кодировка консоли в java

Кодировка консоли в Win не совпадает с системной кодировкой (которая Charset.defaultCharset()). А знать ее часто бывает полезно. Например, запускаемые внешние процессы могут возвращать описания ошибок на русском -- и фиг вы их прочитаете. Конечно, можно просто зашить кодировку Cp866 для русской версии -- но это неправославное решение. А ну как другая локаль будет? Хотелось бы иметь возможность спросить, в какой кодировке работает наша консоль.

Я долгое время был уверен, что такого метода в jdk не предусмотрено. Но, совершенно случайно, раскапывая исходники стандартной библиотеки обнаружил решение для Sun JDK 1.6+ -- приватный статический метод java.io.Console.encoding()

final Class<Console> clazz = Console.class;
final Method method = clazz.getDeclaredMethod( "encoding", new Class[0] );
method.setAccessible( true );
final String encoding = ( String )method.invoke( null );


возвращает на моей системе Cp866, как положено.