This is the first day of my participation in the Gwen Challenge in November. Check out the details: the last Gwen Challenge in 2021

This article is excerpted from The Flyweight Pattern of Design Patterns Should be Learned this way.

1 Background

A programmer changed int to Integer because of a method parameter in the production environment. Because of the money involved, the company lost a lot of money after the launch, and the programmer was fired. Believe it or not, read on. Let’s start with some code:


public static void main(String[] args) {

        Integer a = Integer.valueOf(100);
        Integer b = 100;

        Integer c = Integer.valueOf(129);
        Integer d = 129;

        System.out.println("a==b:" + (a==b));
        System.out.println("c==d:" + (c==d));
}

Copy the code

And what do you think it’s going to do? After running the program, we found something wrong and got an unexpected result, as shown in the figure below.

One must look at this and ask, why is that? This result is due to the share element schema used by Integer. Look at the source code for Integer,


public final class Integer extends Number implements Comparable<Integer> {...public static Integer valueOf(int i) {

						if (i >= IntegerCache.low && i <= IntegerCache.high)
								return IntegerCache.cache[i + (-IntegerCache.low)];
						return newInteger(i); }... }Copy the code

IntegerCache low and high


private static class IntegerCache {
  / / the minimum
  static final int low = -128;
  // Maximum value, customizable
  static final int high;
  // Cache the array
  static final Integer cache[];

  static {
    // The maximum value can be changed by property configuration
    int h = 127;
    String integerCacheHighPropValue =
      sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
    // This value is used if the corresponding property is set
    if(integerCacheHighPropValue ! =null) {
      try {
        int i = parseInt(integerCacheHighPropValue);
        i = Math.max(i, 127);
        // The maximum array size is integer.max_value
        h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
      } catch( NumberFormatException nfe) {
        // If the property cannot be parsed into an int, ignore it.
      }
    }
    high = h;
        
    cache = new Integer[(high - low) + 1];
    int j = low;
    // All values in the low-high range are instantiated and stored in an array for cache use
    for(int k = 0; k < cache.length; k++)
      cache[k] = new Integer(j++);

    // range [-128, 127] must be interned (JLS7 5.1.7)
    assert IntegerCache.high >= 127;
  }

  private IntegerCache(a) {}}Copy the code

The valueOf() method in the Integer source code makes a conditional judgment. If the target value is between -128-127, the value is directly fetched from the cache. Otherwise, a new object is created. In fact, Integer initializes the cache the first time it is used, with a minimum range of -128 and a default maximum of 127. Initialize all data from low to high and store it in the cache array. The default value is -128-127 (256). To be precise, the 256 objects are stored in the memory address of the array. Now, again, someone might say, well, why is the default -128-127, why isn’t it -200-200 or something else? So why does the JDK do this?

The Java API explains it like this:

Returns an Integer instance representing the specified int value. If a new Integer instance is not required, this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values. This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range

The general meaning is:

Data from 128 to 127 is the most frequently used in the int range. In order to reduce the memory consumption caused by the frequent creation of objects, we use the free element mode to improve the space and time performance.

JDK increase the scope of this default is not immutable, we can before use by setting – Djava. Lang. Integer. IntegerCache. High = XXX or Settings – XX: AutoBoxCacheMax = XXX to modify the cache scope, the diagram below:

Later, I found a more plausible explanation:

In fact, when this feature was first introduced in Java 5, the range was fixed at -127 to +127. Later, in the Java 6 range maximum map to Java. Lang. Integer. IntegerCache. High, VM parameter allows us to set high figures. Depending on our application use case, it has the flexibility to adjust performance. Why should this number range be chosen from -127 to 127? This is considered a widely used integer range. The first time you use Integer in a program, you have to spend extra time caching instances.

The Java Language Specification is as follows:

Ideally, boxing a given primitive value p, would always yield an identical reference. In practice, this may not be feasible using existing implementation techniques. The rules above are a pragmatic compromise. The final clause above requires that certain common values always be boxed into indistinguishable objects. The implementation may cache these, lazily or eagerly. For other values, this formulation disallows any assumptions about the identity of the boxed values on the programmer’s part. This would allow (but not require) sharing of some or all of these references.

This ensures that in most common cases, the behavior will be the desired one, without imposing an undue performance penalty, especially on small devices. Less memory-limited implementations might, for example, cache all char and short values, as well as int and long values in the range of -32K to +32K.

2 Comparison of Integer and int

  1. Since an Integer variable is actually a reference to an Integer object, two Integer variables generated by new are never equal (because new generates two objects with different memory addresses).

Integer i = new Integer(100);
Integer j = new Integer(100);
System.out.print(i == j); //false

Copy the code
  1. If an Integer variable is compared with an int variable, the result is true as long as the values of the two variables are equal.

Integer i = new Integer(100);
int j = 100; System.out.print(i == j);//true

Copy the code
  1. Integer variables that are not generated by new are compared to variables generated by new Integer() and the result is false. (1) Non-new generated Integer variables refer to objects in the Java constant pool, while new Integer() generated variables refer to objects newly created in the heap, which have different addresses in memory. If the value of a variable is between -128-127, the Java API will eventually treat the Interger as a new Integer(I).

Integer i = new Integer(100);
Integer j = 100;
System.out.print(i == j); //false

Copy the code
  1. For two non-new generated Integer objects, the comparison result is true if the values of the two variables are in the range -128 to 127, and false if the values are not in the range

3 Expanding knowledge

In the JDK, not only ints are used, but the following wrapper types are also used to cache values. The scope of the cache is different, as shown in the following table:

Basic types of The size of the The minimum value The maximum Wrapper type The cache scope Whether customization is supported
boolean Bloolean
char 6bit Unicode 0 Unic ode 2(16)-1 Character 0 ~ 127 no
byte 8bit – 128. + 127 Byte – 128 ~ 127 no
short 16bit – 2 (15) 2 (15) – 1 Short – 128 ~ 127 no
int 32bit – 2 (31) 2 (31) – 1 Integer – 128 ~ 127 support
long 64bit – 2 (63). 2 (63) – 1 Long – 128 ~ 127 no
float 32bit IEEE754 IEEE754 Float
double 64bit IEEE754 IEEE754 Double
void Void

Do you think it’s worth it?

4 Use the free mode to implement the database connection pool

As another example, we often use database Connection pooling, because the main performance cost of using Connection objects is when establishing and closing connections. In order to improve the performance of Connection objects during invocation, Connection objects are created and cached before invocation. The value is directly taken from the cache when it is used, and then put back to achieve the purpose of resource reuse. The code is as follows.


public class ConnectionPool {

    private Vector<Connection> pool;

    private String url = "jdbc:mysql://localhost:3306/test";
    private String username = "root";
    private String password = "root";
    private String driverClassName = "com.mysql.jdbc.Driver";
    private int poolSize = 100;

public ConnectionPool(a) {

        pool = new Vector<Connection>(poolSize);

        try{
            Class.forName(driverClassName);
            for (int i = 0; i < poolSize; i++) { Connection conn = DriverManager.getConnection(url,username,password); pool.add(conn); }}catch(Exception e){ e.printStackTrace(); }}public synchronized Connection getConnection(a){
        if(pool.size() > 0){
            Connection conn = pool.get(0);
            pool.remove(conn);
            return conn;
        }
        return null;
    }

    public synchronized void release(Connection conn){ pool.add(conn); }}Copy the code

Such connection pooling, commonly used in open source frameworks, can effectively improve the underlying performance.

Pay attention to “Tom play architecture” reply to “design pattern” can obtain the complete source code.

Tom play architecture: 30 real cases of design patterns (attached source code), the challenge of annual salary 60W is not a dream

This article is “Tom play structure” original, reproduced please indicate the source. Technology is to share, I share my happiness! If this article is helpful to you, welcome to follow and like; If you have any suggestions can also leave a comment or private letter, your support is my motivation to adhere to the creation. Pay attention to “Tom bomb architecture” for more technical dry goods!