TreadLocal实现线程之间数据隔离

1.概述:ThreadLocal被称为线程区域变量,用于在线程中保存数据,在ThreadLocal里保存的数据仅属于当前线程,别的线程访问不到,实现了线程之间的数据隔离,在同一个线程的不同方法中,可以通过ThreadLocal传递数据,无需大量的形参进行传值。

2.ThreadLocal的常用方法:

set方法:

public void set(T value) {
        //获取当前执行线程的对象
        Thread t = Thread.currentThread();
        //获取当前线程对象的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        //如果map不为空,以ThreadLocal为key,将value值保存在map中
        //否则先创建出ThreadLocalMap集合并将值保存在map中
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

get方法:

public T get() {
        //获取当前执行线程的对象
        Thread t = Thread.currentThread();
        //获取当前线程的ThreadLocalMap集合
        ThreadLocalMap map = getMap(t);
        //如果当前map不为空,以自身ThreadLocal对象为key,取出map中的值并返回
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

remove方法:

public void remove() {
         //获取当前线程的ThreadMap集合对象
         ThreadLocalMap m = getMap(Thread.currentThread());
         //如果ThreadMap集合不为空,就删除以当前ThreadLocal对象为key的value值
         if (m != null)
             m.remove(this);
     }

在以上的三个方法中,我们可以看出通过ThreadLocal对象保存的值,都会保存在当前线程对象的ThreadLocalMap集合中,并且以ThreadLocal自身为key保存在集合中, 无论是存值还是取值都是以ThreadLocal自身为key操作ThreadLocalMap集合的,接下来,让我们学习一下ThreadLocalMap到底是什么?

3.ThreadLocalMap的内部结构:

//Thread类中的代码
ThreadLocal.ThreadLocalMap threadLocals = null;

从上面的代码中看出,每个Thread对象(即每个线程),都会定义一个ThreadLocalMap的集合对象,也就是ThreadLocal对象将数据保存的位置。

ThreadLocalMap部分代码:

static class ThreadLocalMap {
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
        private static final int INITIAL_CAPACITY = 16;
        
        //存放值的数组
        private Entry[] table;
        
        //构造方法
        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);
        }
}

首先,ThreadLocalMap是ThreadLocal类中的一个内部类,类中定义了一个Entry类型的数组来保存值,Entry类为ThreadLocalMap中的内部类,通过构造方法可以看出ThreadLocalMap的key为ThreadLocal类型。

注意:

        (1)虽然ThreadLocalMap是ThreadLocal类中的一个内部类,但ThreadLocalMap声明是在Thread类中的,属于Thread类的成员变量

        (2)ThreadLocalMap虽然也是键值对集合,但是它并没有实现Map集合,与HashMap不同,它的数据结构仅仅是一个Entry类型的数组。

        (3)每一个Thread线程对象都会有一个ThreadLocalMap类型的成员变量,用来保存属于这个线程的数据,并以ThreadLocal对象为key

结合图片理解一下:

---------------------------------------------------------------------------------------------------------------------------------

4.案例实现:

public class Demo01 {
	
	public static ThreadLocal<String> roleLocal=new ThreadLocal<String>();
	
	public static void main(String[] args) throws InterruptedException {
		Thread t1=new Thread(new Runnable() {
			
			@Override
			public void run() {
				roleLocal.set("苏妲己");
				show();
				Sample.dosth();
			}
		},"线程1");
		
		Thread t2=new Thread(new Runnable() {
			
			@Override
			public void run() {
				roleLocal.set("闻太师");
				show();
				Sample.dosth();
			}
		},"线程2");
		
		t1.start();
		t2.start();
		
		t1.join();
		t2.join();
		
		System.out.println("执行结束!");
	}
	
	public static void show() {
		System.out.println("show:"+Thread.currentThread().getName()+"角色分配为:"+roleLocal.get());
	}
}
class Sample{
	public static void dosth() {
		System.out.println("dosth:"+Thread.currentThread().getName()+"角色为:"+Demo01.roleLocal.get());
	}
}

在上面的代码中,我们首先创建出了一个ThreadLocal类型的roleLocal对象, 然后创建出两个不同的线程,在线程中先使用roleLocal分别保存不同的角色名称,然后调用show()方法通过roleLocal取出角色名称,再调用Sample的dosth()方法通过roleLocal取出角色名称。

运行结果:

 

从运行结果看出,两个线程分别保存自己的角色名称,实现了线程之间的数据隔离,在show()方法和Sample类的dosth()方法之间,ThreadLocal实现了同一个线程中不同方法之间的数据传递。

ThreadLocal的应用场景:

        (1)实现线程之间的数据隔离(比如:案例中两个线程之间分别存入不同的角色名称)

        (2)跨函数传值,例如,案例中show()方法和Sample类的dosth()方法之间的角色名称数据,避免了通过形参传递,降低了类或者方法之间的耦合度。

注意事项:

        (1)一个ThreadLocal对象在一个线程中只能存放一个值,可以使用多个ThreadLocal对象在一个线程中存放多个值。

        (2)使用完TheadLocal保存的数据后,应该在finally代码块中调用ThreadLocal的remove()方法,避免内存泄露。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值