ThreadLocal重新理解

面试的时候问了threadlocal的用法,之前只是了解到threadlocal是为了解决多线程并发问题,具体什么原理不是很清楚,重新学习了一下。
threadlocal是thread的一个局部变量,threadlocal里面有一个threadlocalMap,这个map里面,key是threadlocal变量,value是用户存放的变量。其实它解决多线程并发问题的根本原因是,threadlocal是thread的局部变量,既然是局部变量,别的线程自然是访问不到。
我在面试时列举了一个threadlocal的用法,是在获取jedis客户端的时候,代码是这样写的:

ThreadLocal threadLocal = new ThreadLocal()
....
Jedis jedis = threadLocal.get();
if (jedis == null) {
			jedis = jedisPool.getResource();
		}

我看到这段代码时,我记得看了日常的set和get操作,这个都是没有什么作用的,没有初始化的操作,每次获取都是null,那为什么还要这么获取一次呢。
查了一下代码,初始化的地方有两处,一处是pipeline的操作,一处是事务的操作。
事务的初始化:

上面的获取连接操作后增加一个lockConn操作
...
public void lockConn(Jedis conn) {
		threadLocal.set(conn);
	}
...
事务内业务逻辑
...
事务处理完毕后调用以下释放连接的操作(感觉这里有漏洞)
public void unLockConn() {
		threadLocal.set(null);
	}

然后有了一点眉目,事务的操作需要在同一个connection上,那么需要在每次拿连接的时候都拿到的是当前线程的同一个connection,用threadllocal再合适不过。事务完成的时候释放threadlocal里的变量就可以。
pipeline的操作也是一样的道理,需要用同一个连接批量传输数据。然后等待服务端的返回结果。
到这里,threadlocal的应用场景是明了了,主要是把连接放在threadlocal里,这样拿连接的时候还是用的老连接,保证了事务的操作控制在一个连接上;但是多线程并发这一块好像没有体现,redis本身虽然是单线程,但业务如果是多线程操作redis的话,就是线程不安全的了。
在网上看到了一个有意思的例子,感觉说的很贴切,虽然目前还没有在项目中发现应用场景:

     public class ThreadLocalTest {  
     
        static class ResourceClass {  
        //初始化两个threadlocal实例
            public final static ThreadLocal RESOURCE_1 =   new ThreadLocal();  
            public final static ThreadLocal RESOURCE_2 =   new ThreadLocal();  
        }  
      
        static class A {  
        //两个更新value的值
            public void setOne(String value) {  
                ResourceClass.RESOURCE_1.set(value);  
            }  
            public void setTwo(String value) {  
                ResourceClass.RESOURCE_2.set(value);  
            }  
        }  
      
        static class B {  
            public void display() {  
                System.out.println(ResourceClass.RESOURCE_1.get()  + ":" + ResourceClass.RESOURCE_2.get());  
            }  
        }  
      
        public static void main(String []args) {  
            final A a = new A();  
            final B b = new B();  
            for(int i = 0 ; i < 15 ; i ++) {  
                final String resouce1 = "线程-" + I;  
                final String resouce2 = " value = (" + i + ")";  
                new Thread() {  
                    public void run() {  
                    try {  
                        a.setOne(resouce1);  
                        a.setTwo(resouce2);  
                        b.display();  
                    }finally {  
                        ResourceClass.RESOURCE_1.remove();  
                        ResourceClass.RESOURCE_2.remove();  
                    }  
                }  
            }.start();  
            }  
        }  
    }  

贴一下结果
线程-0: value = (0)
线程-8: value = (8)
线程-7: value = (7)
线程-6: value = (6)
线程-10: value = (10)
线程-11: value = (11)
线程-12: value = (12)
线程-14: value = (14)
线程-13: value = (13)
线程-1: value = (1)
线程-2: value = (2)
线程-3: value = (3)
线程-9: value = (9)
线程-4: value = (4)
线程-5: value = (5)

这个例子确实证明了,在多线程运行的时候,a和b的值是一致的,确实没有相互影响。具体这一块的应用场景,等见到了再补充。

你可能感兴趣的:(原理学习)