2016-02-01 1 views
2

Java-класс Properties является поточно-класса в соответствии с его документацией:Должен ли я получить блокировку свойств перед циклом setProperety?

Этот класс является поточно-: несколько потоков могут совместно использовать один Свойства объекта без необходимости внешней синхронизации.

Из-за этой причине, у меня есть привычка поддерживать свои свойства в HashMap реализации Map, которая не является поточно-, но гораздо более легкий. Более конкретно, для обеспечения безопасности потоков требуются дополнительные блокирующие механизмы, которые будут влиять на производительность. Я могу легко избежать этого, просто выделив инициализацию моего свойства в статическом инициализаторе класса, что гарантирует его завершение, прежде чем я буду использовать любые вызовы get в методах экземпляра того же класса.

Это до сих пор было просто повествованием, которое привело меня к реальному вопросу. В конце концов мне нужно вернуться к API, который может принимать только «Свойства» в качестве параметра, например, DriverManager.getConnection(String,Properties). Мне нужно преобразовать Map в Properties.

Так первая попытка будет выглядеть как-то вроде этого:

Properties properties = new Properties(); 
    this.propertyMap.forEach((k,v)->{properties.setProperty(k, v);}); 
    connection = DriverManager.getConnection(url, properties); 

Очевидная проблема, или, может быть, не столь очевидно, как я избегал использования актуальной для цикла, то, что я использую повторный вызов Properties.setProperty. Если Properties действительно потокобезопасен, то это должно означать, что каждый вызов setProperty синхронизирован и имеет отдельные механизмы блокировки/разблокировки.

Не было бы лучше в таком случае, чтобы я вручную заблокировал весь экземпляр Properties, как в коде ниже?

Connection connection; 
Properties properties = new Properties(); 
synchronized (properties) { 
    // Properties is implemented as thread-safe. As it adds 
    // additional thread locking, it's use is localized to just 
    // here to avoid consequential performance issues. We will 
    // do a last minute conversion from Map to Properties right here. 
    this.propertyMap.forEach((k,v)->{properties.setProperty(k, v);}); 
    connection = DriverManager.getConnection(url, properties); 
} 

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

+1

Не существует синхронизации точек в локальном экземпляре 'Свойства'. Я бы подумал о блокировке на 'ProperyMap', но тогда каждый раз, когда вы хотели обновить карту, вам также нужно будет блокировать ее, чтобы предотвратить возможную мутацию между потоками. – MadProgrammer

+3

блокировки являются реентерабельными. также неустранимые синхронизации бывают быстрыми. так что это, возможно, не стоит беспокоиться. –

+0

@MadProgrammer Я избегаю одновременной мутации экземпляра «Карта», следуя соглашению, а не блокировке. Это то, что я пытался объяснить в разделе, посвященном моему фактическому вопросу. Но почему нет смысла синхронизировать локальный экземпляр «Свойства»? – YoYo

ответ

0

Я сделал неверные выводы, основанные на неправильном бенчмаркинге. Несмотря на то, что я попытался провести какой-то разминку, этого никогда не было достаточно.

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

Измененная Заключение

Заключение сейчас, что методы действительно в значительной степени не имеет значения. Я все еще вижу, что HashMap в целом немного лучше, чем Properties, но этого недостаточно, чтобы заставить меня выбирать производительность по читабельности.

Согласно предложению @Holger, я бы предложил просто использовать метод Properties.putAll(other). Это быстро, и работает так же, как и другие.

Однако, если вы используете это в многопоточной среде, я бы предложил использовать HashMap и тщательно рассмотреть параллельный доступ. Обычно это легко достижимо без необходимости чрезмерной блокировки/синхронизации.

Я думаю, что это был хороший урок.

Ниже приведены более нормализованные измерения. Я немного обманул, взглянув на глаз и выбрав образец без выбросов, вместо того, чтобы усреднять/медиализировать несколько образцов. Просто для того, чтобы избежать сложности (и дополнительной работы) этого или получить внешний инструмент.

 
+----------------------------------+----------+--------+ 
|    Name    | Unlocked | Locked | 
+----------------------------------+----------+--------+ 
| putAll->Properties    | 1,644 | 1,429 | 
| forEach->setProperty->Properties | 1,474 | 1,740 | 
| stream->setProperty->Properties | 1,484 | 1,735 | 
| loop->setProperty->Properties | 2,022 | 1,606 | 
| forEach->put->Properties   | 1,590 | 1,411 | 
| stream->put->Properties   | 1,538 | 1,514 | 
| loop->put->Properties   | 1,380 | 1,666 | 
| putAll->Map      | 1,380 | 509 | 
| forEach->put->Map    | 935  | 915 | 
| stream->put->Map     | 927  | 888 | 
| loop->put->Map     | 880  | 1,015 | 
+----------------------------------+----------+--------+ 

Методика

Методы испытаний, в том же порядке, как и в приведенной выше таблице, с p будучи Properties и mMap в качестве мишени:

p.putAll(SOURCEMAP); 
    SOURCEMAP.forEach(p::setProperty); 
    SOURCEMAP.entrySet().stream().forEach((e)->{p.setProperty(e.getKey(), e.getValue());}); 
    for (Map.Entry<String,String> e:SOURCEMAP.entrySet()) p.setProperty(e.getKey(), e.getValue()); 
    SOURCEMAP.forEach(p::put); 
    SOURCEMAP.entrySet().stream().forEach((e)->{p.put(e.getKey(), e.getValue());}); 
    for (Map.Entry<String,String> e:SOURCEMAP.entrySet()) p.put(e.getKey(), e.getValue()); 
    m.putAll(SOURCEMAP); 
    SOURCEMAP.forEach(m::put); 
    SOURCEMAP.entrySet().stream().forEach((e)->{m.put(e.getKey(), e.getValue());}); 
    for (Map.Entry<String,String> e:SOURCEMAP.entrySet()) m.put(e.getKey(), e.getValue()); 

Полный Исходный код доступен в GitHub: http://github.com/jdesmet/properties-benchmarking.

Смежные вопросы