Performance test for Java ' i++ ' counters
- The so-called volatile
- Synchronized Synchronization Primitives
- JDK1.5 's Atomiclong
- Java8 Longadder Vs Atomiclong
- Summary: comparison, which should be used?
Preface
in the write multi-threading, we inevitably use the counter, today to analyze the Java provided to our counters and their performance tests.
1. The so-called volatile
I also wrote about the role of volatile in the previous article: when we write a variable, it is immediately flushed to the main memory, ensuring that the variable is visible to other threads, and that the thread does not update the data in its own private memory without synchronizing to the main memory. And in later versions of JDK, volatile semantics are enhanced, which limits the rules for partial memory rearrangement to ensure thread safety
Although volatile is used to ensure thread safety, it is important to note that volatile-modified variables are not thread-safe. This means that volatile is only an auxiliary function, and it does not guarantee that the modified variable is atomic.
Look at the simple code of the paragraph:
Public class javavolatile { volatile Static inti =0; Public Static void Main(String args[])throwsinterruptedexception{class Newthread extends Thread { Public void Run() { for(intj =0; J <1000000; ++J) {++i; } } }DoubleStart = System.currenttimemillis (); Newthread NT1 =NewNewthread (); Newthread Nt2 =NewNewthread (); Newthread Nt3 =NewNewthread (); Nt1.start (); Nt2.start (); Nt3.start (); Nt1.join (); Nt2.join (); Nt3.join ();DoubleEnd = System.currenttimemillis (); System.out.println (i); System.out.println ("Time:"+ (End-start)); }}
From the picture we can see that the volatile modifier is not guaranteed to be atomic (the correct result should be 30000), for example, when thread A and thread B simultaneously operate the I, the B thread updates locally, and then two threads flush into memory. The problem arises. But as the JVM is optimized, the use of volatile is less, and we can use several of the following, but it is a good idea to generally use volatile to modify the Boolean type.
Note: The volatile modifier and its own independent variable operation is atomic, n++ not, but if n = m+1 or n = ture is atomic, the reason can think of the principle of volatile .
2.Synchronized Synchronization Primitives
Synchronized can modify a method or a block of code, and at some point it is guaranteed that only one thread can access the method or block of code.
The synchronized principle is that every object in Java has a monitor, or lock, that accesses the object synchronized the method or block of code is locked until the access is complete or an exception is thrown to release the lock.
This shows that synchronized is guaranteed to synchronize, after all, involves lock lock mechanism, but the efficiency is relatively low, after all, involves lock and unlock, and in the case of lock other thread access will be blocked.
Code
Public class javasynchronize { Public Static inti =0;Static synchronized voidIncre () {++i; } Public Static void Main(String args[])throwsInterruptedexception {class Newthread extends thread{ Public void Run(){ for(intj =0; J <1000000; ++J) {incre (); } } }DoubleStart = System.currenttimemillis (); Newthread NT1 =NewNewthread (); Newthread Nt2 =NewNewthread (); Newthread Nt3 =NewNewthread (); Nt1.start (); Nt2.start (); Nt3.start (); Nt1.join (); Nt2.join (); Nt3.join ();DoubleEnd = System.currenttimemillis (); System.out.println (i); System.out.println (End-start); }}
Results:
3.jdk1.5 's Atomiclong
Java SE5 introduced the Atomiclong Atom class, which encapsulates a similar i++ operation, so we can use it directly and simply.
Public class javathread { Public Static void Main(String args[])throwsinterruptedexception {//atomicinteger i = new Atomicinteger (0);Atomiclong i =NewAtomiclong (0); Class Newthread extends thread{ Public void Run(){ for(intj =0; J <1000000; ++J) {I.addandget (1); } } }DoubleStart = System.currenttimemillis (); Newthread NT1 =NewNewthread (); Newthread Nt2 =NewNewthread (); Newthread Nt3 =NewNewthread (); Nt1.start (); Nt2.start (); Nt3.start (); Nt1.join (); Nt2.join (); Nt3.join ();DoubleEnd = System.currenttimemillis (); System.out.println (I.get ()); System.out.println (End-start); }}
In the code I annotated the Atomicinteger, is an atomic integer type, Atomiclong is a long integer, in the actual test process Atomicinteger faster than Atomiclong
It's Atomicinteger.
Therefore, we choose the counter or according to the actual situation to choose and according to their own machine conditions to choose the most efficient.
4.java8 longaddr Vs atomiclong
The latest java8 updated a lot of things, including the new atomic counter LONGADDR, since it can be updated to show that its efficiency is better ^_^, the use of the Atomiclong with the front is no different, and it is actually used to replace the Atomiclong.
Look at the code:
Public class javalongaddr { Public Static void Main(String args[])throwsinterruptedexception {longadder La =NewLongadder (); Class Countthread extends thread{ Public void Run(){ for(inti =0; I <1000000; ++i) {la.increment (); } } }DoubleStart = System.currenttimemillis (); Countthread Ct1 =NewCountthread (); Countthread CT2 =NewCountthread (); Countthread CT3 =NewCountthread (); Ct1.start (); Ct2.start (); Ct3.start (); Ct1.join (); Ct2.join (); Ct3.join ();DoubleEnd = System.currenttimemillis (); System.out.println (LA); System.out.println (End-start); }}
I tested several times to take an average of about 50ms, actually the fastest reached 30ms, indicating that the efficiency of longadder and atomiclong efficiency is very high, faster than just one times. But Java8 does not have the so-called Integeradder, only increased longadder and doubleadder, if interested why become more efficient can search on the Internet, there are many ^_^.
If you want to learn more about Atomiclong and longaddr, see http://www.importnew.com/9560.html.
The analysis is clear.
5. Summary: The comparison, which should be used?
In my opinion, or the specific situation of the specific analysis, everyone needs different, the environment is not the same, if we want their own program to achieve maximum efficiency, then test it! Find the most efficient in person! , I can only provide a train of thought and general situation.
Here are my tests, each of which takes 5 sets of data (in MS):
Threadnum |
synchronzied |
Atomiclong |
longaddr |
1 |
36/42/39/33/32 |
29/52/26/30/28 |
23/28/29/37/24 |
2 |
60/68/104/69/51 |
66/97/80/96/100 |
57/42/46/37/46 |
4 |
153/281/276/178/235 |
144/160/145/149/121 |
63/62/59/65/71 |
8 |
497/587/168/245/531 |
447/385/240/351/310 |
116/103/93/99/91 |
16 |
366/549/767/724/568 |
623/890/835/554/886 |
174/157/153/176/163 |
The above data for the average calculation, so that everyone can better see
Threadnum |
Synchronized |
Atomiclong |
Longadder |
1 |
36 |
33 |
28 |
2 |
70 |
88 |
46 |
4 |
225 |
144 |
64 |
8 |
50W |
347 |
100 |
16 |
595 |
758 |
165 |
The results are obvious, longadder efficiency is significantly higher than atomiclong and synchronized, but in a single-threaded case the difference is not big, occasionally the other two more than Longadder, multi-threaded counter Certainly with Longadder, the efficiency is not a little bit, but Atomicinteger still need to be tested.
In addition, if we want to multi-thread synchronization operation is not only counters, there are other operations, etc., you can consider choosing synchronized.
Finish
Performance test for Java ' i++ ' counters