The previous post attempted to look at the most basic component of Thread synchronization and estimate its cost. The conclusion was that the cost is too low to be considered an issue.
Now I want to add another element to testing. Does the number of threads that might hold the lock significantly impact synchronization performance? I'm still not considering actual contention for the lock (I'll get to that). But how well is the synchronization code optimized to handle many threads, even when there is no contention.
My conclusion here? That the number of threads does impact synchronization performance, however, that impact is minimal to the point of unimportance. It's possible that continuing to increase the number of threads will eventually find a break point where performance degrades very quickly, but the change was fairly constant up to 1000 threads. The increase in time is small enough that it's not worth fussing over. If you're building a massive application that has many thousands of threads, you should probably run your own tests to be sure of the impact, but otherwise I wouldn't worry about it.
The code and results are included at the end of this post, so you're free to draw your own conclusions.
I ran the tests on FreeBSD 10 with OpenJDK 1.7.0_60-b19 (some of that version number may be FreeBSD-specific version information). Feel free to grab the code and try it out on your favorite JVM. Of course, hardware will have a non-trivial effect on overall run time, but the ratio of run times between the various numbers of threads should be fairly consistent within a specific implementation. Whether other JVMs have different performance characteristics is a question for someone else to answer.
Test Code:
public class Test2 { public static boolean run; public static void main(String[] args) { Test2 app = new Test2(); app.go(); } private void go() { int loops = 30000000; int[] sizes = new int[] {1, 1, 5, 10, 50, 100, 500, 1000}; int runsEach = 30; for (int size : sizes) { System.out.println(""); System.out.println(">> Testing with " + size + " threads"); long total = 0; for (int i = 0; i < runsEach; i++) { startThreads(size); total += doTest(loops); stopThreads(); java.lang.System.gc(); try { Thread.sleep(900); } catch (InterruptedException e) { System.out.println("!! Main Thread interrupted"); } } System.out.println(">> Average time = " + total / runsEach); System.out.println(">> Average time per call = " + total / (runsEach * loops)); } } private TestThread[] threads; private void startThreads(final int num) { threads = new TestThread[num]; run = true; for (int i = 0; i < num; i++) { threads[i] = new TestThread(); threads[i].start(); } } private long doTest(final int loops) { long start, end; TestThread test = new TestThread(); start = System.nanoTime(); for (int i = 0; i < loops; i++) { test.work(); } end = System.nanoTime(); System.out.println("Run time " + (end - start)); return end - start; } private void stopThreads() { run = false; for (int i = 0; i < threads.length; i++) { try { threads[i].join(); } catch (InterruptedException e) { System.out.println("!! Thread interrupted before successful join"); } } } private class TestThread extends Thread { public void run() { while (run) { try { Thread.sleep(10); } catch (InterruptedException e) { // Just continue with the loop } } } public synchronized void work() { float f = 1; for (int i = 0; i < 10; i++) { f += f; } } } }
Results:
>> Testing with 1 threads Run time 795962042 Run time 786286857 Run time 199196969 Run time 16297397 Run time 17163671 Run time 16824990 Run time 16407745 Run time 17554201 Run time 15890607 Run time 17541246 Run time 16434331 Run time 16932517 Run time 16085874 Run time 15215291 Run time 15619357 Run time 15115641 Run time 15780876 Run time 15205568 Run time 15643645 Run time 15472839 Run time 15974359 Run time 15157174 Run time 15617533 Run time 15438992 Run time 15468485 Run time 15507157 Run time 15244974 Run time 15875522 Run time 15191091 Run time 15783097 >> Average time = 73729668 >> Average time per call = 2 >> Testing with 1 threads Run time 15386418 Run time 15348036 Run time 15663421 Run time 15212932 Run time 15658743 Run time 15153505 Run time 15835270 Run time 15256209 Run time 15382945 Run time 15965559 Run time 15231225 Run time 15880726 Run time 15271493 Run time 175648894 Run time 178731461 Run time 190533321 Run time 199313983 Run time 199060600 Run time 199415887 Run time 198765814 Run time 199796152 Run time 198772032 Run time 199028302 Run time 199572685 Run time 199027456 Run time 199549007 Run time 198859863 Run time 198762869 Run time 198742303 Run time 198504792 >> Average time = 117777730 >> Average time per call = 3 >> Testing with 5 threads Run time 199484393 Run time 198697191 Run time 200076825 Run time 199277548 Run time 199980755 Run time 199297630 Run time 199438981 Run time 199254148 Run time 198903016 Run time 199377172 Run time 199109173 Run time 200369934 Run time 199544113 Run time 200267803 Run time 199367557 Run time 200217676 Run time 199541885 Run time 199430942 Run time 199129716 Run time 198968970 Run time 198969677 Run time 199830897 Run time 198897138 Run time 199976410 Run time 199251960 Run time 199445897 Run time 199301249 Run time 198974016 Run time 198842029 Run time 199144413 >> Average time = 199412303 >> Average time per call = 6 >> Testing with 10 threads Run time 199150382 Run time 199320156 Run time 199138419 Run time 199160883 Run time 199245564 Run time 199021987 Run time 198903988 Run time 199016954 Run time 199358554 Run time 199310135 Run time 200188974 Run time 199290615 Run time 199183679 Run time 199238515 Run time 199217762 Run time 199035672 Run time 199041539 Run time 199471882 Run time 199150993 Run time 199165169 Run time 199301659 Run time 198992886 Run time 199086269 Run time 199257415 Run time 198941664 Run time 199705914 Run time 199222760 Run time 199960150 Run time 199671478 Run time 200217657 >> Average time = 199298989 >> Average time per call = 6 >> Testing with 50 threads Run time 200530217 Run time 199892436 Run time 197262962 Run time 201208398 Run time 199715748 Run time 199992779 Run time 200659787 Run time 200165258 Run time 199800937 Run time 199635001 Run time 200087977 Run time 200112382 Run time 200363229 Run time 200298460 Run time 199473022 Run time 199927887 Run time 199505967 Run time 200106173 Run time 200292659 Run time 200843640 Run time 199689815 Run time 200025039 Run time 200644594 Run time 199538623 Run time 199061118 Run time 199193134 Run time 200095598 Run time 199744275 Run time 199588208 Run time 198247397 >> Average time = 199856757 >> Average time per call = 6 >> Testing with 100 threads Run time 200634862 Run time 200379624 Run time 200683595 Run time 200798071 Run time 199676874 Run time 200784278 Run time 200763565 Run time 200921517 Run time 200344951 Run time 200623614 Run time 200946937 Run time 200934182 Run time 200399438 Run time 200897918 Run time 200741948 Run time 200843386 Run time 201104921 Run time 200010681 Run time 200800678 Run time 200658461 Run time 200565042 Run time 200107552 Run time 200443788 Run time 200282941 Run time 200987905 Run time 201173373 Run time 200345061 Run time 200222440 Run time 200900207 Run time 199372010 >> Average time = 200578327 >> Average time per call = 6 >> Testing with 500 threads Run time 203454398 Run time 205942401 Run time 210786881 Run time 206963343 Run time 202776739 Run time 205442114 Run time 208851151 Run time 207165043 Run time 215251977 Run time 209431195 Run time 205501259 Run time 215273283 Run time 212493174 Run time 212313821 Run time 206062559 Run time 208761225 Run time 209276176 Run time 210185340 Run time 206295473 Run time 208948272 Run time 208813577 Run time 209519561 Run time 211457223 Run time 208937196 Run time 205003769 Run time 211591797 Run time 208652449 Run time 207622638 Run time 210153556 Run time 211430555 >> Average time = 208811938 >> Average time per call = 6 >> Testing with 1000 threads Run time 221468163 Run time 220505584 Run time 221465052 Run time 221587124 Run time 219965864 Run time 222025735 Run time 229103364 Run time 223751433 Run time 232994489 Run time 232980384 Run time 228709413 Run time 231892879 Run time 234950720 Run time 235469612 Run time 233690739 Run time 234489554 Run time 225850296 Run time 232385003 Run time 232641676 Run time 236887098 Run time 227695483 Run time 228017456 Run time 229519798 Run time 231757513 Run time 231118086 Run time 230468418 Run time 232784509 Run time 232030684 Run time 232966890 Run time 227513589 >> Average time = 229222886 >> Average time per call = 7
No comments:
Post a Comment