In other words, stack long wrote a function a while ago, test 0 bug on the line, the line is also running well, no one feedback bug for many days, super cool.

If there is no problem, there is a big problem.

Recently, there was a customer feedback about some data confusion problem, it was very weird to look at the code, it turned out to be a global variable problem, which led to thread insecurity in the case of concurrency, and was later hit in the face by colleagues!!

Careful use of global variables, I have been emphasizing in the company, did not expect such low-level problems actually happened in their own body, say really ashamed ah.

We started with the way Spring injected objects:

@Autowired
private Object object;
Copy the code

Since Spring is a singleton by default, there is no problem writing it this way. Later, as the business grew and required multiple different business instances, I changed it to this way:

@Setter
private Object object;
Copy the code

This @setter is Lombok’s annotation to generate setters methods, which is pretty low-level, considering that simultaneous manipulation of this object will almost certainly overwrite it, causing the problem mentioned above.

Write such a low-level bug, I am not afraid of embarrassed to send out, we all remember it.

In addition, LET me summarize a few scenarios where global variables can be used sparingly:

1, SimpleDateFormat

SimpleDateFormat forbids static or global shared variables because it is thread unsafe, as stated in alibaba’s Java Development Manual:

The latest full version can be obtained by following the public account “Java Technology Stack” and replying to “Manual”.

Why is SimpleDateFormat not thread-safe?

Take a look at its format method source:

You can see that the Calendar variable is also a global variable, and there are dirty variables that can be set in multi-threaded situations.

So, if you want to use SimpleDateFormat, create a SimpleDateFormat object every time you use it, thread isolation.

2. Resource connection

Resource connections include database connections, FTP connections, Redis connections, etc., which also need to be careful with global variables, a amount of use of global variables, will encounter the following problems:

1) When the connection is closed, the connection being operated by others may be closed, resulting in the interruption of services of other threads;

2) Because it is a global variable, multiple instances may be created during creation. When the connection is closed, only one object connection may be closed, resulting in other connections not closed, and finally the connection is exhausted and the system is unavailable;

3. Number-crunching

This is a classic problem. If you want to use multiple threads to accumulate a number and other operations, do not use the global base type variable, as shown below:

private long count;
Copy the code

In multithreading, the value that one thread gets may have been modified by another thread, resulting in an inaccurate value.

, of course, the above examples can be solved by lock, also can use global atomic classes (Java. Util. Concurrent. Atomic. Atom *) for processing, such as:

private AtomicInteger count = new AtomicInteger();
Copy the code

Note that this atomic class has no thread-safety issues with global variables, and uses the CAS algorithm to ensure data consistency.

However, Ali recommends LongAdder for better performance:

java.util.concurrent.atomic.LongAdder

4. Global Session

Consider the following example:

@Autowired
protected HttpSession session;
Copy the code

Global injection a Session object. In Spring, such global injection is ok by default, including request and Response objects, can be obtained through global injection.

Is this thread safe?

Don’t!

In this way, when the Bean is initialized, instead of injecting the real object, Spring injects a proxy object that gets the real object when it is actually used.

In addition, Spring uses ThreadLocal variables when injecting such objects, which ensures that request/ Response /session objects are thread-safe.

I won’t expand on the details, but you can check out this article for detailed introduction and testing.

Since it’s thread safe, be careful if I actively invalidate the session object in a method and rebuild it:

session.invalidate();
session = request.getSession();
Copy the code

So the session object becomes A real object, not A proxy object, and it becomes one of those multithreaded security issues THAT I talked about at the beginning of this article. If A session gets messed up online, user A can see user B’s data. Isn’t that scary?

So, even if you can use them this way, be careful and use them at the method level.

conclusion

Today, stack long summarized how I write the low-level bug of the global variable, also summarized the next careful use of the global variable 4 situations, I believe that we have encountered similar problems, I hope to help you less pit.

Global variables are good, but we also have to be careful to use ah, must consider whether to cause multi-thread security issues, otherwise it will cause major problems.

If you have any problems with global variables, please share them in the comments.