ãšã³ããªãŒ
ããã¯ç§ã®æåã®èšäºã®ç¿»èš³ã§ãã å¥åŠãªããšã«ãJavaã«å°å¿µããããšã«ããŸããã ãã®èšäºã§ã¯ãJavaã§çºçããæååããŒã¿åã®å€æŽã«ã€ããŠèª¬æããŸãã
éèŠïŒ17ã®æŽæ°ã§ã¯ãJava 7ã¯ãŸã èšäºã«ã€ããŠäœãå€æŽããŠããŸããã
æåã®æåé åã®åå²[]
Stringã¯ã©ã¹ã®çŸåšã®å®è£ ã«ã¯ã4ã€ã®ã€ã³ã¹ã¿ã³ã¹ãã£ãŒã«ãããããŸããæååæåãå«ãæåã®char []å€é åãintãªãã»ããã¯å€é åã§äœ¿çšãããæåã®æåã®ã€ã³ããã¯ã¹ãint countã¯äœ¿çšãããæåæ°ãint hashã¯ãã®æååã®èšç®ãããããã·ã¥ã³ãŒãã®ãã£ãã·ã¥ãããå€ã§ãã ã芧ã®ãšãããã»ãšãã©ã®å Žåãæååã®å€ã¯offset = 0ããã³count = value.lengthã«ãªããŸãã ãã®ã«ãŒã«ã®å¯äžã®äŸå€ã¯ãviaString.substringã¡ãœãããŸãã¯ãã®ã¡ãœããã䜿çšããã¡ãœããïŒsplitãªã©ïŒãåŒã³åºããŠæååãäœæããå Žåã«å¯èœã§ãã
String.substringã¯ãæåã®char []å éšé åãå ã®æååãšå ±æããæååãäœæããŸãã
- äžç·ã«äœ¿çšããŠã¡ã¢ãªãç¯çŽããŸãã
- String.substringã¡ãœããã®å®è¡æéãäžå®ã«ããŸãïŒOïŒ1ïŒïŒã
åæã«ããã®ãããªå®è£ ã§ã¯ãã¡ã¢ãªãªãŒã¯ãçºçããå¯èœæ§ããããŸãã倧ããªæååããå°ããªéšåæååãæœåºãã倧ããªæååãäžèŠã«ãªã£ãå Žåã§ããå ã®æååã®å€§ããªæåé åãžã®ãªã³ã¯ããããŸãã ãããåé¿ããå¯äžã®æ¹æ³ã¯ãã³ã³ã¹ãã©ã¯ã¿ãŒnew StringïŒStringïŒãåŒã³åºãããšã§ããããã«ãããæåã®é åã®ã³ããŒã匷å¶çã«äœæããŸããã€ãŸããå°ããªã芪ãããå°ããªæååãåæããŸãã
Java 1.7.0_06ã§ã¯ããªãã»ãããã£ãŒã«ããšã«ãŠã³ããã£ãŒã«ããStringã¯ã©ã¹ããåé€ãããŸããã ããã¯ãæåã®é åãå ±æã§ããªããªã£ãããšãæå³ããŸãã ããã§ãäžèšã®ã¡ã¢ãªãªãŒã¯ãå¿ããŠãæ°ããStringïŒStringïŒã³ã³ã¹ãã©ã¯ã¿ãŒãåã³äœ¿çšããããšã¯ã§ããªããªããŸãã æ¬ ç¹ãšããŠãString.substringã¡ãœããã¯ã以åã®å®æ°ãšã¯å¯Ÿç §çã«ç·åœ¢ã®è€éããæã€ããã«ãªã£ãããšãåžžã«èŠããŠããå¿ èŠããããŸãã
ããã·ã¥ããžãã¯ã®å€æŽ
åãæŽæ°ã§Stringã¯ã©ã¹ã«å°å ¥ãããå¥ã®å€æŽïŒæ°ããããã·ã¥ã¢ã«ãŽãªãºã ã ãªã©ã¯ã«ã«ãããšãæ°ããã¢ã«ãŽãªãºã ã¯ããã·ã¥ã³ãŒãã®ããè¯ãååžãæäŸããããã·ã¥ããŒã¹ã®ã³ã¬ã¯ã·ã§ã³ïŒHashMapãHashtableãHashSetãLinkedHashSetãWeakHashMapãConcurentHashMapïŒã®ããã©ãŒãã³ã¹ãæ¹åããã¯ãã§ãã èšäºã®åé ã§èª¬æããå€æŽãšã¯ç°ãªãããããã®å€æŽã¯å®éšçãªãã®ã§ãããããã©ã«ãã§ã¯ãªãã«ãªã£ãŠããŸãã
ãæ°ã¥ããããããŸãããããããã®å€æŽã¯ãã³ã¬ã¯ã·ã§ã³ããŒãæååã§ããå Žåã«ã®ã¿åœãŠã¯ãŸããŸãã ãããã®å€æŽãæå¹ã«ããã«ã¯ãã·ã¹ãã ããããã£jdk.map.althashing.thresholdã®å€ãè² ã§ãªãå€ã«èšå®ããå¿ èŠããããŸãïŒããã©ã«ãã§ã¯-1ã§ãïŒã ãã®å€ã¯ãã³ã¬ã¯ã·ã§ã³ã®ãµã€ãºã®ãããå€ã§ããããã®åŸãæ°ããããã·ã¥ã¢ã«ãŽãªãºã ã䜿çšãããŸãã å°ããªä¿®æ£ïŒããã·ã¥ã¢ã«ãŽãªãºã ã¯ãååãªã¡ã¢ãªããªãå Žåã«ã®ã¿å€æŽãããŸãã ã³ã¬ã¯ã·ã§ã³ããµã€ãº= 160ããã³jdk.map.althashing.threshold = 200ã§åé åžãããå Žåãã³ã¬ã¯ã·ã§ã³ãµã€ãºã320ã«å¢å ããå Žåã«ã®ã¿ããã·ã¥æ¹æ³ãå€æŽãããŸãã
Stringã¯ã©ã¹ã«ã¯hash32ïŒïŒã¡ãœãããããããã®çµæã¯int hash32ãã£ãŒã«ãã«ãã£ãã·ã¥ãããŸãã åãæååã«å¯Ÿããhash32ïŒïŒã¡ãœããã®çµæã¯ãJVMã®èµ·åã«ãã£ãŠç°ãªãå ŽåããããŸãïŒå®éãSystem.currentTimeMillisïŒïŒãšSystem.nanoTimeã®2ã€ã®åŒã³åºããåæåã«äœ¿çšãããããå®éã«ã¯ã»ãšãã©ç°ãªããŸãïŒã ãã®çµæãåãã³ã¬ã¯ã·ã§ã³ã«å¯Ÿããå埩ã¯ãããã°ã©ã ã®èµ·åããšã«ç°ãªãå ŽåããããŸãã å®éãç§ã¯ãã®æ¹æ³ã«å°ãé©ããã hashCodeã¡ãœããã®å®éã®å®è£ ãååã«æ©èœããå Žåããªãå¿ èŠãªã®ã§ããããïŒ hash32ïŒïŒã¡ãœããã䜿çšããŠååŸãããè¡çªã®æ°ã確èªããããšã«ããŸããã String.hash32ïŒïŒã¡ãœããã¯ãããªãã¯ã§ã¯ãããŸããããHashMapã¯ã©ã¹ã®å®è£ ãèŠãŠããããåŒã³åºãæ¹æ³ã決å®ããŸããã åçïŒsun.misc.Hashing.stringHash32ïŒæååïŒã 100äžè¡ãå«ããã¹ãã§ã¯ãString.hashCodeã¡ãœããã䜿çšããè€æ°ã®è¡çªãšæ¯èŒããŠãã¡ãœããã¯304ã®è¡çªãè¿ããŸããã ç§ãã¡ã¯ãããªãæ¹åãåŸ ã€ã¹ãã ãšæããŸãã
æ°ããããã·ã¥ããžãã¯ã¯ããã«ãã¹ã¬ããã³ãŒãã«æ·±å»ãªåœ±é¿ãäžããå¯èœæ§ããããŸã
Oracleã¯ãHashMapãHashtableãHashSetãLinkedHashSetãWeakHashMapã®åã¯ã©ã¹ã§ããã·ã¥ãå®è£ ãããšãã«ãã¹ãç¯ããŸããã ConcurentHashMapã®ã¿ã«ãã®ãšã©ãŒã¯å«ãŸããŸããã åé¡ã¯ããã¹ãŠã®é䞊åã¯ã©ã¹ã«ãã£ãŒã«ããããããšã§ãïŒ
/** * . */ transient final int hashSeed = sun.misc.Hashing.randomHashSeed(this);
ããã¯ãäžèšã®ã³ã¬ã¯ã·ã§ã³ãäœæãããã³ã«ãsun.misc.Hashing.randomHashSeedã¡ãœãããåŒã³åºãããããšãæå³ããŸãã 次ã«ãrandomHashSeedã¡ãœããã¯java.util.Random.nextIntã¡ãœãããåŒã³åºããŸãã ãåãã®ããã«ãRandomã¯ã©ã¹ã¯ãã«ãã¹ã¬ããã«ããŸãé©ããŠããŸããããã©ã€ããŒãã¯ã©ã¹ã®AtomicLongã·ãŒããã£ãŒã«ããå«ãŸããŠããŸãã ã¢ãããã¯ã¯å¹³åçãªè² è·ã®äžã§ã¯ããŸãæ©èœããŸãããéãè² è·ã®äžã§ã¯äžååã§ãã
ãã®çµæãã»ãšãã©ãã¹ãŠã®æ¢ç¥ã®ããŒãµãŒïŒããŒãµãŒïŒã圱é¿ãåããã¯ã©ã¹ã®å°ãªããšã1ã€ã䜿çšãããããHTTP / JSON / XMLãåŠçããå€ãã®è² è·ã®é«ãWebã¢ããªã±ãŒã·ã§ã³ããã®ãšã©ãŒã®åœ±é¿ãåããå¯èœæ§ããããŸãã ãããã®ããŒãµãŒã¯ãã¹ãŠããã¹ãããããããã³ã¬ã¯ã·ã§ã³ãäœæã§ããŸããããã«ãããæ¯ç§äœæããããããã³ã¬ã¯ã·ã§ã³ã®æ°ãå¢ããŸãã
ãã®åé¡ã解決ããã«ã¯ïŒ
1. ConcurrentHashMapãã¹ïŒã·ã¹ãã ããããã£jdk.map.althashing.thresholdãå®çŸ©ãããŠããå Žåã«ã®ã¿randomHashSeedã¡ãœãããåŒã³åºããŸãã ãã ããããã¯JDKã«ãŒãã«éçºè ã®ã¿ãå©çšã§ããŸãã
/** * . */ private transient final int hashSeed = randomHashSeed(this); private static int randomHashSeed(ConcurrentHashMap instance) { if (sun.misc.VM.isBooted() && Holder.ALTERNATIVE_HASHING) { return sun.misc.Hashing.randomHashSeed(instance); } return 0; }
2.ããã«ãŒã®æ¹æ³ïŒã¯ã©ã¹sun.misc.Hashingãå€æŽããŸãã éåžžã«ãã£ããããŸããã ããã§ããããè¡ãããšã«ããå Žåã¯ããããè¡ãããšãã§ããŸããjava.util.Randomã¯ã©ã¹ã¯finalã§ã¯ãããŸããã ããšãã°ãå®æ°å€ãè¿ãããšã«ããããããå±éããŠnextIntã¡ãœããããªãŒããŒã©ã€ãã§ããŸãã 次ã«ãRandomããç¶æ¿ããã¯ã©ã¹ã«èšå®ããŠããã£ãŒã«ãsun.misc.Hashing.Holder.SEED_MAKERãå€æŽããå¿ èŠããããŸãã ãã®ãã£ãŒã«ãããã©ã€ããŒãã§éçã§ãããæçµçãªãã®ã§ããããšãå¿é ããªãã§ãã ãã-ãªãã¬ã¯ã·ã§ã³ã圹ç«ã¡ãŸãã
ãŸãšã
- Java 1.7.0_06以éãString.substringã¡ãœããã¯ãäœæããæååããšã«åžžã«char []æåã®æ°ããé åãäœæããŸãã ããã¯ããã®ã¡ãœããã以åã®ããŒãžã§ã³ã®ããã«å®æ°ãšæ¯èŒããŠç·åœ¢ã®è€éããæã€ããšãæå³ããŸãã ãã®å€æŽã®çµæãæååã¯ä»¥åããã4ãã€ãå°ãªããªããString.substringã¡ãœããã«èµ·å ããã¡ã¢ãªãªãŒã¯ã確å®ã«æé€ãããŸãã
- åãæŽæ°ããéå§ããŠãhash32ãšåŒã°ããããã·ã¥ã®2çªç®ã®ã¡ãœãããStringã¯ã©ã¹ã«ç»å ŽããŸããã ãã®ã¡ãœããã¯ãããªãã¯ã§ã¯ãªããsun.misc.Hashing.stringHash32ïŒStringïŒã¡ãœãããåŒã³åºãããšã«ãã£ãŠã®ã¿ãªãã¬ã¯ã·ã§ã³ãªãã§ã¢ã¯ã»ã¹ã§ããŸãã ãã®ã¡ãœããã¯ããµã€ãºãã·ã¹ãã ããããã£jdk.map.althashing.thresholdã®å€ãè¶ ããå Žåãããã·ã¥ããŒã¹ã®ã³ã¬ã¯ã·ã§ã³ã«ãã£ãŠJDK 7ã§äœ¿çšãããŸãã ããã¯å®éšçãªæ¹æ³ã§ãããã³ãŒãã§äœ¿çšããããšã¯ãå§ãããŸããã
- Java 1.7.0_06以éããã¹ãŠã®æšæºã®éãã«ãã¹ã¬ããã³ã¬ã¯ã·ã§ã³ã«ã¯ãæ°ããããã·ã¥ã¢ã«ãŽãªãºã ã«ããæãŸãããªãå¯äœçšããããŸãã ãã®ãšã©ãŒã¯ãæ¯ç§å€ãã®ãããã³ã¬ã¯ã·ã§ã³ãäœæãããã«ãã¹ã¬ããã¢ããªã±ãŒã·ã§ã³ã§ã®ã¿çºçããŸãã
èªåãã
Javaã®æååãæåã®é åãå ±æããŠãããšããäºå®ã¯ãããããæ°žç¶çã§ããããšã瀺åããŠããŸãã æ°žç¶æ§é ã¯ãå€æŽæã«ä»¥åã®ããŒãžã§ã³ããã¹ãŠä¿æããæ§é ãšåŒã°ããããšãç¥ãããŠããŸãã ããã¯ãéšåæååã¡ãœããã®å®è¡æéãäžå®ã«ããããã«äœ¿çšãããã¡ã¢ãªéãåæžããæé©åãšããŠãæ瀺çã«è¡ãããŸããã ãã ãããã®æé©åã®å©ç¹ã¯ããã»ã©å€§ãããªãããããã®ã¢ã€ãã¢ã¯Javaã®ããŒãžã§ã³7ã§æŸæ£ãããŸããã
.NETã§ã¯ãæååã¯æåã¯æ°žç¶çã§ã¯ãããŸããã§ããã ãšãªãã¯ã»ãªãããŒãã«ããèå³æ·±ãèšäºãžã®ãªã³ã¯ããããŸããããã®çç±ã«ã€ããŠè©³ãã説æããŠããŸãã
èªãã§ãããŠããããšãã
ãã®èšäºãã圹ã«ç«ãŠã°å¹žãã§ãã