Multi-threading learning summary (four)

ThreadLocal及InheritableThreadLocal

1. What is ThreadLocal?

In simple terms, then the JDK When using ThreadLocal variable maintenance, use ThreadLocal variable for each thread to provide a copy of the independent variables, so each thread can independently change their copy without affecting other the threads corresponding copy.

Code demonstrates:

package com.my.thread;
   public class ThreadDemo2 {
       private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
           @Override
           public Integer initialValue() {
               return 0;
           }
       };
       static class ThreadDemo implements Runnable {
           @Override
           public void run() {
               for (int i = 0; i < 1000; i++) {
                   threadLocal.set(threadLocal.get() + 1);
               }
               System.out.println("thread :" + Thread.currentThread().getId() + " is" + threadLocal.get());
           }
       }
       public static void main(String[] args) {
           for (int i = 0; i < 10; i++) {
               new Thread(new ThreadDemo()).start();
           }
       }
   }
结果:
    thread :11 is1000
    thread :12 is1000
    thread :13 is1000
    thread :14 is1000
    thread :17 is1000
    thread :16 is1000
    thread :15 is1000
    thread :18 is1000
    thread :19 is1000
    thread :20 is1000

As can be seen from the above results, the output of all operations will not be affected between threads. Because no shared property caused confusion 1000. op instructions.

ThreadLocal principle analysis (of the code)

ThreadLocal.ThreadLocalMap threadLocals = null;
        protected T initialValue() {
            return null;
        }
        void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }
        public T get() {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null) {
                ThreadLocalMap.Entry e = map.getEntry(this);
                if (e != null) {
                    @SuppressWarnings("unchecked")
                    T result = (T)e.value;
                    return result;
                }
            }
            return setInitialValue();
        }
        private T setInitialValue() {
            T value = initialValue();
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
            return value;
        }
        public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }
        ThreadLocalMap getMap(Thread t) {
           return t.threadLocals;
        }

to sum up

From the very beginning we use ThreadLocal, you can override the initialValue () method, which is assigned to the initial value.
1. If the method must first call to set the set value (T value), then will first use getMap (t) to obtain the current thread ThreadLocalMap collection of objects.
If the judgment will be created and assigned by createMap (Thread t, T firstValue) is null.
If not null, the description has been ThreadLocalMap collection, you can directly add to the collection.
2. If the first call to get () method, will go getMap (t) Gets a collection of objects ThreadLocalMap the current thread.
If not, get it from ThreadLocalMap collection is null.
If null, it will execute setInitialValue () method, and by createMap (thread t , T firstValue) created and assigned.

When here, they should understand it. When we ThreadLocal object definition, does not create a collection for ThreadLocalMap thread. But calls get () and set method, created to judge.
So is each thread a ThreadLocalMap has its own set of threads for their own use.

Then when the end of the thread is how to deal with it?

private void exit() {
            if (group != null) {
                group.threadTerminated(this);
                group = null;
            }
            target = null;
            threadLocals = null;
            inheritableThreadLocals = null;
            inheritedAccessControlContext = null;
            blocker = null;
            uncaughtExceptionHandler = null;
        }

Can be seen from the above, if the end of the thread calls exit () method performs a threadLocals = null;. Then ThreadLocalMap collection will be null reference, waiting for GC to come clean up the destruction.
Such treatment was no problem, but with thread pool inside is not the same.

    package com.my.thread;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;

    public class ThreadLocalTest {

    	//创建一个Integer本地线程变量
    	private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
    		@Override
    		public Integer initialValue() {
    			return 0;
    		}
    	};
    	static class ThreadDemo implements Runnable {
    		@Override
    		public void run() {
    			for (int i = 0; i < 1000; i++) {
    				threadLocal.set(threadLocal.get() + 1);
    			}
    			System.out.println("thread :" + Thread.currentThread().getId() + " is" + threadLocal.get());
    			//threadLocal.remove();
    		}
    	}
    	public static void main(String[] args) {
    		ExecutorService executorService= Executors.newFixedThreadPool(5);
    		for (int i = 0; i < 10; i++) {
    			executorService.submit(new Thread(new ThreadDemo()));
    		}
    	}

    }

结果:
    thread :12 is1000
    thread :16 is1000
    thread :18 is1000
    thread :16 is2000
    thread :16 is3000
    thread :16 is4000
    thread :18 is2000
    thread :12 is2000
    thread :14 is1000
    thread :20 is1000

Can be seen, while accumulating a thread. This is because in the thread pool thread executed, not killed, but returned to the thread times out waiting for the next task.
When we //threadLocal.remove (); Notes after opening, the result as shown below.

结果:
       thread :14 is1000
       thread :14 is1000
       thread :14 is1000
       thread :14 is1000
       thread :12 is1000
       thread :14 is1000
       thread :12 is1000
       thread :16 is1000
       thread :18 is1000
       thread :20 is1000

We can see, the result is 1000. So in the thread pool using ThreadLocal, ThreadLocal emptied after use as long as the value, you can normally use.

2.InheritableThreadLocal

Why use this InheritableThreadLocal?

First, let's talk about the needs of the scene. When we start a thread A thread B to perform an action, but we need to use some of the values ​​of A ThreadLocal thread in the thread B in this time of need thread A can ThreadLocal B is transmitted to the thread.

Code demonstrates the scene:

package com.my.thread;
public class ThreadLocalTest1 {
        private static  InheritableThreadLocal<Integer> inheritableThreadLocal = new  InheritableThreadLocal<Integer>();
        static class ThreadDemo implements Runnable {
        		@Override
        		public void run() {
        			for (int i = 0; i < 1000; i++) {
        				inheritableThreadLocal.set(inheritableThreadLocal.get() + 1);
        			}
        			System.out.println("thread :" + Thread.currentThread().getId() + " is" + inheritableThreadLocal.get());
        		}
        	}
        	public static void main(String[] args) {
        		inheritableThreadLocal.set(24);
        		for (int i = 0; i < 10; i++) {
        			new Thread(new ThreadDemo()).start();
        		}
        	}
        }
结果:
    thread :12 is1024
    thread :11 is1024
    thread :13 is1024
    thread :14 is1024
    thread :17 is1024
    thread :18 is1024
    thread :19 is1024
    thread :20 is1024
    thread :15 is1024
    thread :16 is1024

Can be seen from the above, 24 from the main thread is passed to the child thread. The last print 1024

InheritableThreadLocal principle analysis

InheritableThreadLocal Source Code:

    public class InheritableThreadLocal<T> extends ThreadLocal<T> {
        protected T childValue(T parentValue) {
            return parentValue;
        }

        ThreadLocalMap getMap(Thread t) {
            return t.inheritableThreadLocals;
        }

        void createMap(Thread t, T firstValue) {
            t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
        }
    }

Thread class part of the code:

    public class Thread implements Runnable {
        private void init(ThreadGroup g, Runnable target, String name,
                              long stackSize, AccessControlContext acc) {
                if (name == null) {
                    throw new NullPointerException("name cannot be null");
                }

                this.name = name.toCharArray();

                Thread parent = currentThread();
                SecurityManager security = System.getSecurityManager();
                if (g == null) {
                    /* Determine if it's an applet or not */

                    /* If there is a security manager, ask the security manager
                       what to do. */
                    if (security != null) {
                        g = security.getThreadGroup();
                    }

                    /* If the security doesn't have a strong opinion of the matter
                       use the parent thread group. */
                    if (g == null) {
                        g = parent.getThreadGroup();
                    }
                }

                /* checkAccess regardless of whether or not threadgroup is
                   explicitly passed in. */
                g.checkAccess();

                /*
                 * Do we have the required permissions?
                 */
                if (security != null) {
                    if (isCCLOverridden(getClass())) {
                        security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
                    }
                }

                g.addUnstarted();

                this.group = g;
                this.daemon = parent.isDaemon();
                this.priority = parent.getPriority();
                if (security == null || isCCLOverridden(parent.getClass()))
                    this.contextClassLoader = parent.getContextClassLoader();
                else
                    this.contextClassLoader = parent.contextClassLoader;
                this.inheritedAccessControlContext =
                        acc != null ? acc : AccessController.getContext();
                this.target = target;
                setPriority(priority);
                if (parent.inheritableThreadLocals != null)
                    this.inheritableThreadLocals =
                        ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
                /* Stash the specified stack size in case the VM cares */
                this.stackSize = stackSize;

                /* Set thread ID */
                tid = nextThreadID();
            }

    }

A brief summary:

Here you can see, InheritableThreadLocal actually inherited a ThreadLocal, and rewrite the getMap (Thread t) and createMap (Thread t, T firstValue) and three methods childValue (T parentValue). Value is assigned to the map set is a variable inheritableThreadLocals thread.
And when we look at the source code of Thread, we can find one of the init () method:
Thread parent = currentThread ();
this.inheritableThreadLocals = ThreadLocal.createInheritedMap (parent.inheritableThreadLocals);
see here, I believe you understand of how it happens.

Simply put, when we use the InheritableThreadLocal. ThreadLocal and use the same. Just finished thread child thread created and initialized, the current parent thread inheritableThreadLocals will transfer to the child thread. This will use the parent thread in the child thread of the data.

Such as the above-described case, the value 24 is provided in the main thread inheritableThreadLocal in the main thread, the thread when the promoter, will pass with inheritableThreadLocal 24 to the child thread. Then the child thread then it inheritableThreadLocal (initial value of the existing 24) do accumulate operations, and end to get 1024

Guess you like

Origin www.cnblogs.com/one-reader/p/11329675.html