Hello~ readers happy New Year! I don’t know whether the Spring Festival holiday has been extended. I just received a notice that the holiday will be extended to February 2nd. In addition, I will have to work at home and be isolated for two weeks after I return. I haven’t tried working from home yet, but I’m afraid it’s already afternoon when I wake up.

preface

During the Spring Festival holiday, little black brother, still lying in bed, received an early warning message from the account checking system, indicating that there are problems in the current system fund checking. As for the problem of funds, they are all big problems. The little black brother hurriedly pulled out the computer, connected to the VPN, logged in the production environment to check the relevant logs.

Through the log, soon black brother to locate the relevant code.

Some students may immediately see the problem here, Long object use! This is really a low-level Bug for comparison. Fortunately, the Leader did not know, and quickly repaired it quietly.

Now, back when Blackie wrote this code, he mistakenly thought that the comparison between two longs would be unboxed automatically and converted to a comparison between two basic numeric types.

Let’s start with a review of Java automatic boxing and unboxing.

Automatic packing and unpacking mechanism

Autoboxing, a syntactic sugar added to JDK5, automatically converts primitive types to their corresponding object wrapper classes when code is compiled. For example, int to Integer and double to double. If the conversion results in the opposite, we call it unpacking.

Here is an example of automatic boxing:

The code li.add(I) above takes place automatically, converting the base data type Long to its wrapper class Long.

Look at the bytecode corresponding to this code.

The bytecode marked with yellow lines is li.add(I). From this we can see that automatic boxing of type long actually calls the long #valueOf method. So the compiler runtime converts the previous code into the following code

Let’s look at an example of automatic unpacking:

Since the Long wrapper object cannot be used for modulo (%) and +=, this code will automatically unbox Long to type Long. Here we also take a look at the compiled bytecode.

The bytecode here is a lot more complicated than it was before, so I’m going to focus on the yellow line. You can see that Long#longValue is called to convert the Long object to Long. So automatically unboxing this example, and eventually the compiler generates bytecode equivalent to the following code:

Each of the eight data types specified in Java has a corresponding wrapper class, which can be automatically boxed and unpacked accordingly.

Here’s a summary:

  1. The automatic boxing mechanism is done by calling the wrapper classvalueOfimplementation
  2. The automatic unpacking mechanism calls the corresponding of the wrapper class**Value, such aslongValue.intValueimplementation

Cache trap

The concept of automatic packing and unpacking is actually quite simple, but it can be stomped if not used properly.

Let’s look at a piece of code:

If you are not quite clear about the above results, congratulations, warm boy black brother helped you mine.

The output above is:

true
false
Copy the code

The main reason for this output is because of LongCache. Autoboxing will call Long#valueOf with the following source code:

As long as the value range is between [-128,127], valueOf returns the values in the longCache. cache array. So aLong/bLong is the same object, and cLong/dLong is two objects that don’t use objects.

The Long#valueOf method reduces the number of objects created by caching and improves spatial and temporal performance.

As for why cache numbers between [-128,127] and not cache more values, or even all values?

This is because the Long range is **[-2^63,2^63]**, which is a total of 2^64. As for the numbers between [-128,127], the JDK designers consider these numbers to be used with high frequency, which I personally consider to be an empirical value.

This cache can cause another problem: lock sharing.

Class A uses the object lock along, while class B uses the object lock blong. It looks like the two objects are not related, but the two objects actually use the same object lock due to the Cache mechanism.

In addition to the Long#valueOf method that has Cache values, Byte, Short, Integer, Character also have corresponding Cache values. The Integer object can change the initial Cache range by running -xx :AutoBoxCacheMax=

.

Technical summary

The automatic boxing and unboxing mechanism greatly reduces the data type conversion code, but also introduces some hidden problems. Here we need to remember:

  1. Cannot be used between all objects= =Comparison, need to useequalsInstead, it is recommendedJDK7To provide theObjects#equalsMethod, which can effectively avoid the null pointer problem in comparison process
  2. Wrapper classes for primitive data types are not suitable as lock objects

Keep these two summaries in mind, readers, and don’t tread on them. It is also recommended that you install FindBugs, a plug-in that scans your code for bugs. FindBugs can scan for both of the above problems, which is pretty impressive.

Object comparison problem:

The lock problem

Help document

  1. Autoboxing and Unboxing “https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html”
  2. Geek Time – “Java Concurrency in action” column

Welcome to pay attention to my public account: procedures to get daily dry goods push. If you are interested in my topics, you can also follow my blog: studyidea.cn