首页 > 其他分享 >ThreadLocal

ThreadLocal

时间:2023-07-10 11:22:57浏览次数:37  
标签:set val void ThreadLocal 线程 public

ThreadLocal

慕课网教程
多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线程安全性。ThreadLocal 是除了加锁这种同步方式之外的一种保证一种规避多线程访问出现线程不安全的方法,当我们在创建一个变量后,如果每个线程对其进行访问的时候访问的都是线程自己的变量这样就不会存在线程不安全问题。
例如:统计在线人数,如果同时登陆人数过多,会导致统计不准确。

构造方法

public ThreadLocal() {
    }

主要方法

// 初始化方法
protected T initialValue() {
      return null;
  }
  // 获取线程数据
  public T get() {
      // 获得当前线程
    Thread t = Thread.currentThread();
    // 通过当前线程获得线程Map
    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);
}
void createMap(Thread t, T firstValue) {
      t.threadLocals = new ThreadLocalMap(this, firstValue);
  }
  // 删除数据
  public void remove() {
    ThreadLocalMap m = getMap(Thread.currentThread());
    if (m != null)
        m.remove(this);
}
//获得线程Map
ThreadLocalMap getMap(Thread t) {
     return t.threadLocals;
 }

实践

问题

当统计用户在线人数时,以下代码:

    // 统计人数的数据
    static Long count = 0L;
    // 假设指定接口的++
   @Test
   public void countTest(){
       // 假设执行了数据库的验证用户信息等等的
       count++;
   }

若使用以上代码进行统计,在并发的情况下会导致数据的不准确。由于 CPU 时执行一段实践这个线程,再去执行另一个线程,如果出现该线程只是获得值,还未进行加一时,就去执行其他线程,就会导致基础数据已经改变,导致加一失败,所以需要改进代码。

首先想到的是加锁:

    // 统计人数的数据
    static Long count = 0L;
    // 假设指定接口的++
    synchronized void _add(){
        // 假设执行了数据库的验证用户信息等等的
       count++;
   }
   @Test
   public void countTest(){
       _add();
   }

虽然以上方法能够解决并发问题,但是因为这个加锁需要排队,使得速度大大降低,浪费资源。所以会想到用 ThreadLocal。

public static ThreadLocal<Long> count = new ThreadLocal(){
       @Override
       protected Object initialValue() {
           return 0L;
       }
   };

   // 假设指定接口的++
    void _add(){
       // 假设执行了数据库的验证用户信息等等的
       count.set(count.get()+1);
   }
   @Test
   public void countTest(){
       _add();
   }

虽然这样也会大大减少排队的问题,但是不同的线程会导致获取的值不一致,所以还应该做线程数据的同步。

static HashSet<Val<Long>> set = new HashSet<>();
   public static ThreadLocal<Val<Long>> count = new ThreadLocal() {
       @Override
       protected Object initialValue() {
           Val<Long> val = new Val<>();
           val.set(0L);
           addSet(val);
           return val;
       }
   };

   synchronized static void addSet(Val val) {
       set.add(val);
   }

   // 假设指定接口的++
   void _add() {
       // 假设执行了数据库的验证用户信息等等的
       Val<Long> val = count.get();
       ;
       val.set(0L);
       val.set(val.get() + 1);
   }

   @Test
   public void countTest() {
       _add();
   }

Val 类

public class Val<T> {
    T t;
    void set(T t){
        this.t =t;
    }
    T get(){
        return t;
    }
}

这样的话,会把排队变成一个线程的排队,而非所有的线程排队,大大节俭排队的花销。当需要统计的时候。把 set 的值遍历求和即可。这样解决了并发的问题,也不会大量的时间进行排队。

标签:set,val,void,ThreadLocal,线程,public
From: https://www.cnblogs.com/jiuxialb/p/17540471.html

相关文章

  • ThreadLocal源码
    使用场景ThreadLocal用来提供线程局部变量。每个线程都会有一份独立的副本,副本之间不存在竞争关系,是线程专属的内存空间。例如:publicclassThreadLocalTest{privatestaticfinalThreadLocal<Integer>threadLocal=newThreadLocal<>();publicstaticvoidma......
  • 深入理解 Java 中的 ThreadLocal
    1.什么是ThreadLocal在Java多线程编程中,我们经常会遇到共享变量的并发访问问题。为了解决这个问题,Java提供了ThreadLocal类,它允许我们在每个线程中存储和访问线程局部变量,而不会影响其他线程的数据。2.使用ThreadLocal使用ThreadLocal很简单,我们只需要创建一个Thre......
  • ThreadLocal
    关于ThreadLocal介绍ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量。ThreadLocal实例通常来说都是privatestatic类型的,用于关联线程和线程上下文。作用提供线程内的局部变量,不......
  • Java并发工具之ThreadLocal
    一、ThreadLocal简介1.ThreadLocal是什么?ThreadLocal字面意思是本地线程,其实更准确来说是线程局部变量,线程类Thread有个变量叫做threadLocals,其类型就是ThreadLocal.ThreadLocalMap类型,他其实不是一个Map类型,但可以暂时理解它是一个Map,键为ThreadLocal对象,值就是要......
  • ThreadLocal 与 synchronized 区别
    老实说,从看到这个帖子的题目开始,就觉得帖子的作者估计是在概念上有所混淆了,于是乎想写个咚咚,同大家分享一下自己的心得。帖子上,讨论的人很多,高手不乏,各抒己见,但不知新手们看明白没有,因此,这里偶以最简洁列表方式来说一说相关问题。1.区别ThreadLocal与synchronizedThread......
  • 图解ThreadLocal
    ThreadLocalTestpublicclassThreadLocalTest{publicstaticvoidmain(String[]args){ThreadLocalthreadLoal_1=newThreadLocal();newThread(()->{threadLoal_1.set("hellot1");System.out.print......
  • 深入学习ThreadLocal
    1、用来干吗的?用于线程在任意的地方去共享数据,而不被其他线程所干扰,2、原理是什么因为每个线程维护一份ThreadLocalMap,使用threadlocal.set(obj)方法是存放在map里面的Entry<<WeekReference>ThreadLocal,Value>数组里3、实际案例,比如写了util类,但是SimplateDateFormate是线程......
  • java子线程中获取父线程的threadLocal中的值
    1packagecom.example.springbootstudy.test.threadLocal;23publicclassBaseTest{45publicstaticfinalInheritableThreadLocal<String>inheritableThreadLocal=newInheritableThreadLocal<>();67publicstaticfinalThrea......
  • ThreadLocal 详解【并发容器】
    ThreadLocal是什么?有哪些使用场景?ThreadLocal是一个本地线程副本变量工具类,在每个线程中都创建了一个ThreadLocalMap对象,简单说ThreadLocal就是一种以空间换时间的做法,每个线程可以访问自己内部ThreadLocalMap对象内的value。通过这种方式,避免资源在多线程间共享。原理:......
  • ThreadLocal在拦截器中的使用
    前置过滤捕获,写入context中,后置删除每个request请求都有自己线程独享的数据,所以用到了ThreadLocal1.添加拦截器@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){......