We know that a security issue occurs when multiple threads access a shared variable.
First look at the following example:
Public classCounter {Private intcount; Public voidAdd () {Try{ for(inti = 0;i<200;i++) {Thread.Sleep (100); This. count++; System.out.println ( This. Count); } }Catch(Exception e) {e.printstacktrace (); } }}
Public classTest { Public Static voidMain (string[] args) {FinalCounter Counter =NewCounter (); NewThread (NewRunnable () { Public voidrun () {counter.add (); }}). Start (); NewThread (NewRunnable () { Public voidrun () {counter.add (); }}). Start (); NewThread (NewRunnable () { Public voidrun () {counter.add (); }}). Start (); }}
The results of the operation are as follows:
If the thread does not have a dirty operation on the data, 3 threads execute, the result will be added to 600, see the result is obviously not, and there is a duplicate of the data. This is because there are 3 threads that operate the same number at the same time, causing the output to repeat numbers.
Workaround:
1. Add the Synchronized keyword to the method. Such as:
Although the result will not repeat, but the synchronized efficiency and its low, the operating speed is obviously slowed down. The reason is that the I variable in the for loop is that each thread has its own local variable, each with no effect, but each thread has to queue into this method and queue up to sleep, which leads to inefficiency
2. Adding synchronized to competitive conditions, we know that each thread is actually competing for the member variable of Count. So you can add this place. Such as:
This is a lot faster than the method, because there is no way to queue into the queue to sleep. You only need to queue up the count value, so the efficiency is faster than the method.
Note that the output statement is not a competition condition, do not have to put in the synchroized inside, here is to let the thread to get the value of the output immediately after, so that the output will not be mixed, no preemption output problem, the same can accumulate to 600,
If the output is placed outside the synchronized, there will be a repetition of the value, because the accumulated value is not immediately output, resulting in output confusion, but still can be added to 600. Knowledge output is unsafe.
3. Using an atomic type, such as changing the int count type of the above code to Atomicinteger count type, we know that getting the value of count and then adding another 1 is a problem that can occur, that is, the result is a repeating number. The Atomicinteger type solves this problem in a synchronous way. Such as:
Results such as:
You can see that the output of the number is not strictly queued, but the data does give you a guarantee that it will add up to 600. This is precisely because it is not strictly queued, this method is much better than the efficiency of the previous two methods.
Theory Summary: Synchronized is an internal lock that is provided to us by the object itself, because each object has a state variable, which is equivalent to a lock, into the synchronization block, changing the variable. When another thread enters, it is necessary to determine whether the variable has changed.
A thread acquires a lock that the native has already held, which can be successful. We know that multiple threads are failing to preempt the same lock at the same time. Because they are mutually exclusive. However, it is possible for a thread to acquire a lock that he has already taken and it can be successful.
See the following example:
Public class Widget { publicsynchronizedvoid dosth () { }}
Public class extends Widget { @Override publicsynchronizedvoid dosth () { Super . Dosth (); }}
Public class Test { publicstaticvoid main (string[] args) { New childwidget (); W.dosth (); } }
The child class calls its own method of the synchroized that lock is the lock of the W object, and the lock of the method in the Super.dosth () parent class in the subclass method is also the lock of the W object. Therefore, do not confuse the locks in the methods that inherit the parent class from the quilt class.
Thus this approach is called the reentrant mechanism of the internal lock, which is also called reentrant lock.
Java Concurrency Programming Note 1-Competitive conditions & Primary knowledge Atomic class & Reentrant Lock