foreword
This article mainly explains how to optimize the locking mechanism
or overcome the problem that multi-threading can cause performance degradation due to locks
ThreadLocal thread variable
There is such a scene, there is a large bucket of water in front, and 10 people go to drink water. In order to ensure thread safety, we need to lock the cups so that
everyone queues up to drink water, because the locked cups are synchronized, and only one
It takes a long time for everyone to drink water from the only
cup. What if we distribute a cup to everyone? Is the time for each person to drink water reduced to 1/10?
Multi-threaded concurrency is also a reason.
Each Thread has its own data storage space (ThreadLocalMap)
, and ThreadLocal stores data in the storage space of the current thread. In the
following example, an arraylist is stored in each thread, not everyone. share an arraylist
public class ThreadLocalTest { public static ThreadLocal threadLocal = new ThreadLocal(); public static ArrayList list = new ArrayList(); public static class Demo implements Runnable { private int i; public Demo(int i) { this.i = i; } @Override public void run() { list.add(i); threadLocal.set(list); System.out.println(threadLocal.get()); } } public static void main(String[] args) throws InterruptedException { ExecutorService es = Executors.newFixedThreadPool(5); for (int j = 0; j < 200; j++) { es.execute(new Demo(j)); } Thread.sleep(3000); System.out.println(list.size()); es.shutdown(); } }
Inside each thread there is a storage area called ThreadLocalMap
It can be seen that ThreadLocal uses set and get to access values.
Only when the thread is completely closed, the data in ThreadLocalMap will be recycled by GC
At this time, there is a problem worth considering.
When we use the thread pool for development, the thread in the thread pool will not be closed, it will only be in an idle state.
That is to say, if we store too large data in the ThreadLocalMap of the current thread , the thread is constantly called and is idle...
Finally, it will lead to memory overflow . The solution is to use the ThreadLocal.remove() method to remove the variable
when the data is not needed.
CAS operation
There is also a mechanism for getting out of the lock, that is, CAS
CAS carries three variables, namely:
V update variable: variable to be returned
E expected value: original value
N new value, new variable passed in
Only when the expected value and the new value are equal, will V=N be set. If they are not equal, it means that the operation will make the data unable to synchronize.
According to the above explanation, it is probably known that CAS is actually protecting the synchronization of the data.
When multiple threads perform CAS operations, it can be imagined that only one thread can successfully update, and then the E and V of other threads will be constantly compared,
so the implementation of the CAS synchronization lock is the same
The concurrent package of CAS operation is in the Atomic package, atomic implements many types,
whether it is AtomicInteger or AtomicReference, all have the same points, please observe their source code:
private volatile V value; private static final long valueOffset;
The above is AtomicReferenc
private volatile int value; private static final long valueOffset;
The above is AtomicIntege
both have value, which is their current actual value
valueOffset holds the offset of the value
A simple AtomicIntege example is given below:
public class AtomicTest { public static AtomicInteger atomicInteger = new AtomicInteger(); //public static AtomicReference atomicReference = new AtomicReference(); public static class Demo implements Runnable{ @Override public void run() { for (int j=0;j<1000;j++){ atomicInteger.incrementAndGet(); //Add 1 to the current value and return the current value } } } public static void main(String[] args) throws InterruptedException { ExecutorService es = Executors.newFixedThreadPool(10); for (int i =0;i<10;i++){ es.submit(new Demo()); } Thread.sleep(5000); System.out.println(atomicInteger); } }
You try to execute it, if it prints 10000, it means thread safety
Using CAS operations has better performance than synchronized locks
Let's look at incrementAndGet()
the source code:
public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; }
Take a look at the getAndAddInt()
source code:
public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { var5 = this.getIntVolatile(var1, var2); } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }
There is a loop here. If you look closely at the source code, you will find that it is native. Although you cannot see the native code, you can see that it has performed a CAS operation here, and constantly compares multiple variables. Only the preset value and the new value are equal. when the loop is exited
var5 is the variable that needs to be updated, var1 and var2 are the default and new values
deadlock
After talking about so many lock-free operations, let's take a look at a deadlock phenomenon.
Two threads occupy each other's locks, and a deadlock situation will occur.
public class DeadLock extends Thread{ protected String suo; public static String zuo = new String(); public static String you = new String(); public DeadLock(String suo){ this.suo=suo; } @Override public void run(){ if (suo==zuo){ synchronized (zuo){ System.out.println("Get the left, is getting the right..."); synchronized (you){ System.out.println("Get the right and succeed"); } } } if (suo==you){ synchronized (you){ System.out.println("Get the right, is getting the left..."); synchronized (zuo){ System.out.println("Get zuo, success"); } } } } public static void main(String[] args) throws InterruptedException { for (int i=0;i<10000;i++){ DeadLock t1 = new DeadLock(zuo); DeadLock t2 = new DeadLock(you); t1.start();t2.start(); } Thread.sleep(50000); } }
As shown in the figure:
There is a deadlock phenomenon between two threads, so unlocking can not only improve performance, but also prevent deadlock.
The address of this article is https://segmentfault.com/a/1190000012218687
More participation content: http://www.roncoo.com/article/index?tn=JAVA