Synchronized keywords
When a Java language keyword is used to modify a method or a code block, it can ensure that at most one thread executes the code at the same time.
When two concurrent threads access this synchronized(this) synchronized code block in the same object object, only one thread can be executed within one time. Another thread must wait for the current thread to execute this code block before it can execute the code block.
However, when one thread accesses one synchronized(this) synchronization code block of an object, another thread can still access the non-synchronized(this) synchronization code block in that object.
It is particularly critical that when a thread accesses a synchronized (this) synchronization code block of an object, other threads will block access to all other synchronized (this) synchronization code blocks in the object.
The third example also applies to other synchronous code blocks. That is, when a thread accesses a synchronized(this) synchronization code block of an object, it obtains the object lock of this object. As a result, other threads access to all synchronous code parts of the object object is temporarily blocked.
The above rules also apply to other object locks.
Code Example
package test160118;public class TestSynchronized { public static void main(String[] args) { Sy sy = new Sy(0); Sy sy2 = new Sy(1); sy.start(); sy2.start(); }}class Sy extends Thread { private int flag ; static Object x1 = new Object(); static Object x2 = new Object(); public Sy(int flag) { this.flag = flag; } @Override public void run() { System.out.println(flag); try { if (flag == 0) { synchronized (x1) { System.out.println(flag+"locked x1"); Thread.sleep(1000); synchronized (x2) { System.out.println(flag+"locked x2"); } System.out.println(flag+"release x1 and x2"); } } if(flag == 1) { synchronized (x2) { System.out.println(flag+"locked x2"); Thread.sleep(1000); synchronized (x1) { System.out.println(flag+"locked x1"); } System.out.println(flag+"release x1 and x2"); } } } catch (InterruptedException e) { e.printStackTrace(); } }}
ThreadLocal lock-free thread enclosing implementation principle
What can ThreadLocal do?
This sentence is hard to say. Let's take a look at some of the difficulties encountered in the actual project: when you call some methods according to some parameters in the project, then the method calls the method, and then call the method across objects, these methods may use some similar parameters, for example, A requires parameters a, b, and c in A. After A calls B, B requires parameters b and c in B, and B calls C methods a and b. At this time, all parameters have to be passed to B. And so on. If there are many methods called, the parameters will become more and more. In addition, when the program needs to add parameters, you need to add parameters to the relevant methods one by one. Yes, it is very troublesome. I believe you have encountered it. This is also some common processing methods for object-oriented in C language. However, our simple processing method is to wrap it into an object and pass it in. This problem can be solved by adding the attributes of the object. However, objects are usually meaningful, so sometimes simple object packaging adds some extended irrelevant attributes to make our class definition very strange, so in these cases When we are structuring complex programs like this, we use some scopes similar to Scope to handle them. The names and uses are more common. Similar to web applications, there will be scopes at context, session, request, and page levels. ThreadLocal can also solve this type of problem, but it is not very suitable to solve this type of problem. When facing these problems, it usually does not pass them in the early stages of scope and object, and believes that parameters will not be added. , When adding parameters, I found that there are many places to be changed. In order not to destroy the structure of the code, it is possible that there are too many parameters, which has reduced the readability of the method code. ThreadLocal is added to handle it. For example, when one method calls another method, 8 parameters are passed in, and one of the parameters is passed in by calling the Nth method layer by layer. At this time, the last method needs to add one parameter. It is natural for the first method to become 9 parameters, but at this time, the relevant methods will be implicated, making the code bloated.
The above mentioned ThreadLocal is a purpose of repairing the problem of losing the enemy, but it is not a particularly recommended way to use it. It also has some similar methods to use it, that is, there are many dynamic calls at the framework level, and some protocols need to be met during the call process. Although we try to be universal, many extended parameters are not easy to consider when defining the protocol, and the version is also upgraded at any time. However, when the framework is extended, the interface is also universal and backward compatibility. We need some extended contents to be convenient and simple.
Simply put, ThreadLocal turns some complex system extensions into simple definitions, making the parts involved in related parameters very easy. Here is our example:
In Spring's transaction manager, the connection obtained by the data source is placed in ThreadLocal. After the program is executed, the connection is obtained from ThreadLocal and then the commit and rollback are done. In use, it is necessary to ensure that the connection obtained by the program through DataSource is obtained from spring. Why do such an operation? Because the business code is completely determined by the application, and the framework cannot require the business code to be written, otherwise the framework will lose the benefit of not allowing the business code to manage the connection. After the business code is cut in, the spring will not pass a connection to the business code area. It must be saved in a place. When the underlying layer passes through ibatis and spring. When a framework such as jdbc obtains the connection of the same datasource, it will call to obtain it according to the rules agreed in spring. Since the execution process is processed in the same thread, the same connection is obtained to ensure that the connection used is the same during commit, rollback and business operations, because only the same connecton can guarantee transactions, otherwise the database itself is not supported.
In fact, in many concurrent programming applications, ThreadLocal plays a very important important role. It does not add locks and easily encloses threads seamlessly, without requiring re-allocating space every time like local variables. Since many spaces are thread-safe, they can repeatedly utilize thread-private buffers.
How to use ThreadLocal?
Define a ThreadLocal variable in any suitable location in the system, which can be defined as a public static type (a ThreadLocal object is directly new). If you want to put data into it, use set(Object), use get() operation, and use remove() when deleting elements. The other methods are non-public methods, and are not recommended.
Here is a simple example (code snippet 1):
public class ThreadLocalTest2 { public final static ThreadLocal <String>TEST_THREAD_NAME_LOCAL = new ThreadLocal<String>(); public final static ThreadLocal <String>TEST_THREAD_VALUE_LOCAL = new ThreadLocal<String>(); public static void main(String[]args) { for(int i = 0 ; i < 100 ; i++) { final String name = "Thread-[" + i + "]"; final String value = String.valueOf(i); new Thread() { public void run() { try { TEST_THREAD_NAME_LOCAL.set(name); TEST_THREAD_VALUE_LOCAL.set(value); callA(); } finally { TEST_THREAD_NAME_LOCAL.remove(); TEST_THREAD_VALUE_LOCAL.remove(); } } } }.start(); } } public static void callA() { callB(); } public static void callB() { new ThreadLocalTest2().callC(); } public void callC() { callD(); } public void callD() { System.out.println(TEST_THREAD_NAME_LOCAL.get() + "/t=/t" + TEST_THREAD_VALUE_LOCAL.get()); }}Here we simulate 100 threads to access the name and value respectively. The values of name and value are deliberately set to the same in the middle to see if there is a concurrency problem. Through the output, we can see that the thread output is not output in order, which means it is executed in parallel, and the thread name and value can be corresponding. In the middle, through multiple methods, the parameters are not passed in the actual call, so how to obtain the corresponding variables. However, in actual systems, they often cross classes. Here they are only simulated in one class. In fact, cross classes are the same result. You can simulate them yourself.
I believe that after seeing this, many programmers are very interested in the principle of ThreadLocal. Let’s see how it is done. Although the parameters are not passed, they can use it like local variables. It is indeed quite magical. In fact, you can tell that it is a setting method. When you see that the name should be related to Thread, then say less nonsense, let’s take a look at its source code. Since we use the most set, get and remove, then start with set:
The set(T obj) method is (code snippet 2):
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value);}First, the current thread is obtained, the same as the guess, and then there is a getMap method, which passes in the current thread. We can first understand that this map is a map related to the thread. Next, if it is not empty, do the set operation. When you track it in, you will find that this is similar to the put operation of HashMap, that is, a piece of data is written into the map. If it is empty, the createMap method is called. After entering, take a look (Code Snippet 3):
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue);}Cashback creates a ThreadLocalMap, and writes the passed parameters and current ThreadLocal as KV structure (Code Snippet 4):
ThreadLocalMap(ThreadLocal firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); table[i] = new Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY);}This is not explained here the structural details of ThreadLocalMap. You only need to know that its implementation is similar to HashMap. There are many methods that do not have implementations Map, because it does not want you to obtain a map through some methods (such as reflection) to further operate it. It is a static inner class in ThreadLocal, default type, and only classes under java.lang can refer to it, so you can think of Thread can refer to it.
Let's look back at the getMap method, because I only know that the map obtained is related to the thread, and through code snippet 3, there is a t.threadLocalMap = new ThreadLocalMap(this, firstValue), I believe you should probably understand that this variable should come from Thread. Let's go in according to the getMap method:
ThreadLocalMap getMap(Thread t) { return t.threadLocals;}Yes, it comes from Thread, and this Thread happens to be the current thread, so go in and look at the definition:
ThreadLocal.ThreadLocalMap threadLocals = null;
This property is in the Thread class, that is, each Thread has a ThreadLocalMap by default, which is used to store thread-level local variables. Usually you cannot assign values to it, because such assignments are usually insecure.
It seems a bit messy, don't worry, let's look back and explore the ideas:
1. There is a property in Thread that is something similar to HashMap, but its name is ThreadLocalMap. This property is of default type, so all classes under the same package can be referenced. Because it is a local variable of Thread, each thread has its own separate map, which does not conflict with each other, so even if ThreadLocal is defined as static threads, there will be no conflict.
2. ThreadLocal and Thread are under the same package. You can refer to this class and operate on it. At this time, each ThreadLocal defines one, use this as the Key, and the value you pass in as the value, and this is the ThreadLocal you define. Therefore, different ThreadLocal variables use set, and the data between each other will not conflict, because their keys are different. Of course, after the same ThreadLocal does two set operations, the last time will be the prevailing.
3. To sum up, when threads are parallel, ThreadLocal can be used like local variables, and is thread-safe, and the data between different ThreadLocal variables has no conflict.
Let's continue to look at the get method and remove method, it's actually simple:
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue();}By calling the getMap method according to the current thread, that is, t.threadLocalMap is called, and then searching in the map, note that the map is found with Entry, that is, the basic structure of KV, because you only write to the value, it will set an e.value to return the value you wrote, because the Key is ThreadLocal itself. You can see that map.getEntry is also obtained through this.
The same remove method is:
public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this);}Also, the map is obtained based on the current thread. If it is not empty, remove, and remove through this.
In addition (2013-6-29), what are the pitfalls of forgetting to write? What pitfalls are there in this ThreadLocal? You should see from the previous example that the ThreadLocal-related object is bound to a map, and this map is a property of the Thread thread. Then there is a problem that if you don’t remove yourself or if you don’t know when to remove in your own program, then the thread will not be logged out, and the data set in it will not be logged out.
On the other hand, unless you clearly understand where this object should be set and where to remove. If it is vague, it is very likely that your code will not go to the remove position, or cause some logical problems. In addition, if it is not removed, you have to wait for the thread to be logged out. In many application servers, threads are reused because there is still overhead in the kernel allocation threads, so it is difficult for threads to be logged out in these applications. Then the data written to ThreadLocal is naturally not easy to be logged out. These may be accidentally hidden and used when we use some open source frameworks, which may cause problems. Finally, I found that when OOM, the data actually came from ThreadLocalMap. I don’t know where this data was set, so you should pay attention to this pit, and more than one person has fallen into this pit.