ThreadLocal 线程私有变量

之前各种加锁保证并发场景下的变量操作的安全性,但是在某些场景下,可以给线程分配其私有变量,在每个线程绑定其私有变量,通过get()和set()方法获取或者修改当前线程私有的变量值,从而避免了线程安全问题

1. 使用 ThreadLocal 类

import java.util.Random;
class House{
    // 全部线程的总共销售额
    int sale=0;
    // 加锁保证线程共有变量的正确性
    public synchronized void saleHouse(){sale++;}
    // 每个线程自己的销售额
    ThreadLocal<Integer> saleVolume = ThreadLocal.withInitial(()->0);
    public void saleCountByThreadLocal(){saleVolume.set(saleVolume.get()+1);}

}
public class ThreadLocalDemo {
    public static void main(String[] args) throws InterruptedException {
        // 模拟10个销售员卖房子
        House house = new House();
        for (int i = 1; i <= 10; i++) {
            new Thread(()->{
                int random = new Random().nextInt(5)+1;
                try {
                    for (int j = 1; j <= random; j++) {
                        house.saleHouse();
                        house.saleCountByThreadLocal();
                    }
                    System.out.println("线程"+Thread.currentThread().getName()+"  "+"销售额="+house.saleVolume.get());
                }finally {
                    // 线程私有变量使用完成之后一定要释放掉---在线程池线程复用的情况下,线程私有变量会导致bug
                    house.saleVolume.remove();
                }
            },String.valueOf(i)).start();
        }

        Thread.sleep(300);
        System.out.println("总销售额 = "+house.sale);
    }
}

输出:

//线程8  销售额=3
//线程6  销售额=1
//线程1  销售额=4
//线程3  销售额=5
//线程2  销售额=2
//线程4  销售额=5
//线程9  销售额=2
//线程5  销售额=4
//线程7  销售额=4
//线程10  销售额=3
//总销售额 = 33

2. ThreadLocal 源码解析

  set()方法

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            map.set(this, value);
        } else {
            createMap(t, value);
        }
    }

   

 

可以看到方法里面都是先通过 Thread.currentThread() 方法获得当前执行该方法的线程,然后通过ThreadLocalMap 找到该线程内的属性值 threadLocals,这个threadLocals是一个map,里面保存的是<当前的ThreadLocal实例, value>的key-value键值对

Thread -> ThreadLocalMap(threadLocals) -> 存储的是<this,value>

  get()方法

    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();
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值