Extremely slow parsing of time zone with the new java.time API

こ雲淡風輕ζ 提交于 2019-12-02 21:57:31

As noted in your question and in my comment, ZoneRulesProvider.getAvailableZoneIds() creates a new set of all the available time zones' string representation (the keys of the static final ConcurrentMap<String, ZoneRulesProvider> ZONES) each time a time zone needs to be parsed.1

Fortunately, a ZoneRulesProvider is an abstract class which is designed to be subclassed. The method protected abstract Set<String> provideZoneIds() is responsible for populating ZONES. Thus, a subclass can provide only the needed time zones if it knows ahead of time of all time zones to be used. Since the class will provide less entries than the default provider, which contains hundreds of entries, it has the potential to significantly reduce the invocation time of getAvailableZoneIds().

The ZoneRulesProvider API provides instructions on how to register one. Note that providers can't be deregistered, only supplemented, so it is not a simple matter of removing the default provider and adding your own. The system property java.time.zone.DefaultZoneRulesProvider defines the default provider. If it returns null (via System.getProperty("...") then the JVM's notorious provider is loaded. Using System.setProperty("...", "fully-qualified name of a concrete ZoneRulesProvider class") one can supply their own provider, which is the one discussed in the 2nd paragraph.

To conclude, I suggest:

  1. Subclass the abstract class ZoneRulesProvider
  2. Implements the protected abstract Set<String> provideZoneIds() with only the needed time zones.
  3. Set the system property to this class.

I did not do it myself, but I am sure it will fail for some reason think it will work.


1 It is suggested in the comments of the question that the exact nature of the invocation might have changed between 1.8 versions.

Edit: more information found

The aforementioned default ZoneRulesProvider is final class TzdbZoneRulesProvider located in java.time.zone. The regions in that class are read from the path: JAVA_HOME/lib/tzdb.dat (in my case it's in the JDK's JRE). That file indeed contains many regions, here is a snippet:

 TZDB  2014cJ Africa/Abidjan Africa/Accra Africa/Addis_Ababa Africa/Algiers 
Africa/Asmara 
Africa/Asmera 
Africa/Bamako 
Africa/Bangui 
Africa/Banjul 
Africa/Bissau Africa/Blantyre Africa/Brazzaville Africa/Bujumbura Africa/Cairo Africa/Casablanca Africa/Ceuta Africa/Conakry Africa/Dakar Africa/Dar_es_Salaam Africa/Djibouti 
Africa/Douala Africa/El_Aaiun Africa/Freetown Africa/Gaborone 
Africa/Harare Africa/Johannesburg Africa/Juba Africa/Kampala Africa/Khartoum 
Africa/Kigali Africa/Kinshasa Africa/Lagos Africa/Libreville Africa/Lome 
Africa/Luanda Africa/Lubumbashi 
Africa/Lusaka 
Africa/Malabo 
Africa/Maputo 
Africa/Maseru Africa/Mbabane Africa/Mogadishu Africa/Monrovia Africa/Nairobi Africa/Ndjamena 
Africa/Niamey Africa/Nouakchott Africa/Ouagadougou Africa/Porto-Novo Africa/Sao_Tome Africa/Timbuktu Africa/Tripoli Africa/Tunis Africa/Windhoek America/Adak America/Anchorage America/Anguilla America/Antigua America/Araguaina America/Argentina/Buenos_Aires America/Argentina/Catamarca  America/Argentina/ComodRivadavia America/Argentina/Cordoba America/Argentina/Jujuy America/Argentina/La_Rioja America/Argentina/Mendoza America/Argentina/Rio_Gallegos America/Argentina/Salta America/Argentina/San_Juan America/Argentina/San_Luis America/Argentina/Tucuman America/Argentina/Ushuaia 
America/Aruba America/Asuncion America/Atikokan America/Atka 
America/Bahia

Then If one finds a way to create a similar file with only the needed zones and load that one instead, the performance issues will probably not surely be resolved.

This problem is caused by ZoneRulesProvider.getAvailableZoneIds() which copied the set of time-zones each time. Bug JDK-8066291 tracked the issue, and it has been fixed in Java SE 9. It will not be backported to Java SE 8 because the bug fix involved a specifiation change (the method now returns an immutable set instead of a mutable one).

As a side note, some other performance issues with parsing have been backported to Java SE 8, so always use the latest update release.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!