multithreading - Java Synchronization Not Working as Expected -
i have "simple" 4 class example reliably shows unexpected behavior java synchronization on multiple machines. can read below, given contract of java sychronized
keyword, broke synchronization
should never printed class testbuffer.
here 4 classes reproduce issue (at least me). i'm not interested in how fix broken example, rather why breaks in first place.
and here output when run it:
java -cp . synctest before adding creating testbuffer before remove broke synchronization 1365192 broke synchronization 1365193 broke synchronization 1365194 broke synchronization 1365195 broke synchronization 1365196 done
update: @gray has simplest example breaks far. example can found here: strange jrc race condition
based on feedback i've gotten others, looks issue may occur on java 64-bit 1.6.0_20-1.6.0_31 (unsure newer 1.6.0's) on windows , osx. nobody has been able reproduce issue on java 7. may require multi-core machine reproduce issue.
original question:
i have class provides following methods:
- remove - removes given item list
- getbuffer - iterates on items in list
i've reduced problem down 2 functions below, both of in same object , they're both synchronized
. unless mistaken, "broke synchronization" should never printed because insidegetbuffer
should set false before remove
can entered. however, in application printing "broke synchronization" when have 1 thread calling remove repeatedly while other calls getbuffer repeatedly. symptom concurrentmodificationexception
.
see also:
very strange race condition looks jre issue
sun bug report:
this confirmed bug in java sun. apparently fixed (unknowingly?) in jdk7u4, have not backported fix jdk6. bug id: 7176993
i think indeed looking @ jvm bug in osr. using simplified program @gray (slight modifications print error message) , options mess with/print jit compilation, can see going on jit. and, can use options control degree can suppress issue, lends lot of evidence being jvm bug.
running as:
java -xx:+printcompilation -xx:compilethreshold=10000 phil.strangeraceconditiontest
you can error condition (like others 80% of runs) , compilation print like:
68 1 java.lang.string::hashcode (64 bytes) 97 2 sun.nio.cs.utf_8$decoder::decodearrayloop (553 bytes) 104 3 java.math.biginteger::muladd (81 bytes) 106 4 java.math.biginteger::multiplytolen (219 bytes) 111 5 java.math.biginteger::addone (77 bytes) 113 6 java.math.biginteger::squaretolen (172 bytes) 114 7 java.math.biginteger::primitiveleftshift (79 bytes) 116 1% java.math.biginteger::multiplytolen @ 138 (219 bytes) 121 8 java.math.biginteger::montreduce (99 bytes) 126 9 sun.security.provider.sha::implcompress (491 bytes) 138 10 java.lang.string::charat (33 bytes) 139 11 java.util.arraylist::ensurecapacity (58 bytes) 139 12 java.util.arraylist::add (29 bytes) 139 2% phil.strangeraceconditiontest$buffer::<init> @ 38 (62 bytes) 158 13 java.util.hashmap::indexfor (6 bytes) 159 14 java.util.hashmap::hash (23 bytes) 159 15 java.util.hashmap::get (79 bytes) 159 16 java.lang.integer::valueof (32 bytes) 168 17 s phil.strangeraceconditiontest::getbuffer (66 bytes) 168 18 s phil.strangeraceconditiontest::remove (10 bytes) 171 19 s phil.strangeraceconditiontest$buffer::remove (34 bytes) 172 3% phil.strangeraceconditiontest::strangeraceconditiontest @ 36 (76 bytes) errors //my little change 219 15 made not entrant java.util.hashmap::get (79 bytes)
there 3 osr replacements (the ones % annotation on compile id). guess is third one, loop calling remove(), responsible error. can excluded jit via .hotspot_compiler file located in working directory following contents:
exclude phil/strangeraceconditiontest strangeraceconditiontest
when run program again, output:
compileroracle: exclude phil/strangeraceconditiontest.strangeraceconditiontest 73 1 java.lang.string::hashcode (64 bytes) 104 2 sun.nio.cs.utf_8$decoder::decodearrayloop (553 bytes) 110 3 java.math.biginteger::muladd (81 bytes) 113 4 java.math.biginteger::multiplytolen (219 bytes) 118 5 java.math.biginteger::addone (77 bytes) 120 6 java.math.biginteger::squaretolen (172 bytes) 121 7 java.math.biginteger::primitiveleftshift (79 bytes) 123 1% java.math.biginteger::multiplytolen @ 138 (219 bytes) 128 8 java.math.biginteger::montreduce (99 bytes) 133 9 sun.security.provider.sha::implcompress (491 bytes) 145 10 java.lang.string::charat (33 bytes) 145 11 java.util.arraylist::ensurecapacity (58 bytes) 146 12 java.util.arraylist::add (29 bytes) 146 2% phil.strangeraceconditiontest$buffer::<init> @ 38 (62 bytes) 165 13 java.util.hashmap::indexfor (6 bytes) 165 14 java.util.hashmap::hash (23 bytes) 165 15 java.util.hashmap::get (79 bytes) 166 16 java.lang.integer::valueof (32 bytes) 174 17 s phil.strangeraceconditiontest::getbuffer (66 bytes) 174 18 s phil.strangeraceconditiontest::remove (10 bytes) ### excluding compile: phil.strangeraceconditiontest::strangeraceconditiontest 177 19 s phil.strangeraceconditiontest$buffer::remove (34 bytes) 324 15 made not entrant java.util.hashmap::get (79 bytes)
and problem not appear (at least not in repeated attempts i've made).
also, if change jvm options bit, can cause problem go away. using either of following cannot problem appear.
java -xx:+printcompilation -xx:compilethreshold=100000 phil.strangeraceconditiontest java -xx:+printcompilation -xx:freqinlinesize=1 phil.strangeraceconditiontest
interestingly, compilation output both of these still show osr remove loop. guess (and big one) delaying jit via compilation threshold or changing freqinlinesize cause changes osr processing in these cases bypass bug otherwise hitting.
see here info on jvm options.
see here , here information on output of -xx:+printcompilation , how mess jit does.
Comments
Post a Comment