Should I get a property lock before the setProperety loop?

The java class Propertiesis a thread safe class as per the documentation:

This class is thread safe: multiple threads can share the same Properties object without the need for external synchronization.

For this reason, I have the habit of maintaining my properties in an implementation HashMap Mapthat is not thread safe, but much easier. More specifically, thread safety requires additional blocking mechanisms that will affect performance. I can easily avoid this by simply splitting the initialization of my property in the static initializer of the class, which guarantees its completion before I use any get calls in the instance methods of the same class.

So far this is just a story that leads me to a real question. In the end, I need to return to the API, which can only accept "Properties" as a parameter, an example of which is DriverManager.getConnection(String,Properties). I need to convert my Mapto Properties.

So, the first attempt will look something like this:

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

The obvious problem, or maybe not as obvious as I avoided using the real for loop, is that I am using a callback Properties.setProperty. If Propertiestruly thread safe, this means that each call is setPropertysynchronized and has separate locking / unlocking mechanisms.

Wouldn't it be better in this case for me to manually block the entire instance Propertiesfirst, as in the code below?

Connection connection;
Properties properties = new Properties();
synchronized (properties) {
  // Properties is implemented as thread-safe. As it adds
  // additional thread locking, it 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);
}

One of the problems that I might have expected is that both manually locking properties and individual calls setPropertiescan cause a dead end, but it seems to work fine.

+2
1

, . , - , .

( ), , , .

, . , 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 m a Map :

  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.

0

Source: https://habr.com/ru/post/1627613/


All Articles