InheritableThreadLocal对象、线程池的使用

InheritableThreadLocal: 可继承的ThreadLocal

使用类InheritableThreadLocal可以在子线程中获得父线程继承下来的值

值继承


public class InheritableThreadLocalExt extends InheritableThreadLocal {
	@Override
	protected Object initialValue() {
		return System.currentTimeMillis();
	}
}
public class Tools {
 
	public static InheritableThreadLocalExt tl = new InheritableThreadLocalExt();
 
}


public class ThreadA extends Thread {
 
	@Override
	public void run() {
		try {
			for (int i = 0; i < 10; i++) {
				System.out.println("在ThreadA线程中取值=" + Tools.tl.get());
				Thread.sleep(100);
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
 
}
public class ThreadB extends Thread {
 
	@Override
	public void run() {
		try {
			for (int i = 0; i < 10; i++) {
				System.out.println("在ThreadB线程中取值=" + Tools.tl.get());
				Thread.sleep(100);
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
 
}
public class Run {
 
	public static void main(String[] args) {
		try {
			for (int i = 0; i < 10; i++) {
				System.out.println("在Main线程中取值=" + Tools.tl.get());
				Thread.sleep(100);
			}
			Thread.sleep(5000);
			ThreadA a = new ThreadA();
			ThreadB b = new ThreadB();
			a.start();
			b.start();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
 
}

测试结果:

在这里插入图片描述

值继承再修改

如果在继承的同事还可以对值进一步的处理就更好了. 可以覆盖父类的clidValue方法


public class InheritableThreadLocalExt extends InheritableThreadLocal {
	@Override
	protected Object initialValue() {
		return System.currentTimeMillis();
	}
 
	@Override
	protected Object childValue(Object parentValue) {
		return parentValue + " 我在子线程加的~!";
	}
}

在这里插入图片描述
但在使用 InheritableThreadLocalExt类需要注意一点的是,如果子线程在取得值的同时,主线程将InheritableThreadLocalExt中的值进行更改,那么子线程取到的值还是旧值.
当必须将在变量中维护的每个线程属性自动传输到创建的任何子线程时,可继承的线程局部变量将优先于普通线程局部变量使用。

线程池中ThreadLocal的使用

在线程池中
ThreadLocal对象的生命周期跟线程的生命周期一样长,那么如果将ThreadLocal对象和线程池一起使用,就可能会遇到这种情况:一个线程的ThreadLocal对象会和其他线程的ThreadLocal对象串掉,
如果使用的话,需要
两种操作:

一、直接在进入线程时remove操作。

二、使用后清空。
需要在finally块中调用remove 方法清除掉当前线程在ThreadLocal中存储的变量,避免线程复用导致的线程变量多个线程之间污染传递;

   private void ansyExcute(MedicalAdviceCatcheResultDTO catcheResultDTO, Map<Long, List<BqyzxxDO>> bqyzxxDOBySYXHMap
            , Map<String, String> map, String authorization) {
        bqyzxxDOBySYXHMap.forEach((k, v) -> {
            executor.execute(() -> {
                try {
                    AsyncRequestContext.setParrentToAnsyToken(authorization);
                    log.info("authorization" + authorization);
                    yzYzzxxExcuteThread.excute(k, v, map, catcheResultDTO);
                } catch (Exception e) {
                    log.error(Thread.currentThread().getId()+"线程执行异常!!!!!"+e.getMessage(), e);
                } finally {
                    AsyncRequestContext.removeAsyncToken();
                }

            });
        });
    }
    ```

```java
import com.alibaba.ttl.TransmittableThreadLocal;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @Classname AsyncRequestContext
 * @Description 异步请求上下文
 * @Date 2021/4/28 18:18
 * @Created by DELL
 */

@Slf4j
public class AsyncRequestContext {
    /**
     * 线程池复上线文信息传递
     */
    public static ThreadLocal<RequestAttributes> tl = new TransmittableThreadLocal<>(); //这里采用TTL的实现

    /**
     * 异步线程池线程上下文信息,支持异步请求
     */
    public static InheritableThreadLocal<String> asyncToken = new InheritableThreadLocal<>();

    public  static String getParentToken(){
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        RequestContextHolder.setRequestAttributes(attributes,true);
        HttpServletRequest httpServletRequest = attributes.getRequest();
        String authorization = httpServletRequest.getHeader("Authorization");
        log.info("Thread ID{},parent authorization{}",Thread.currentThread().getId(),authorization);
        return authorization;
    }



    public  static void setParrentToAnsyToken(String authorization){
        log.info("Ansy Thread ID{},set parent Thread Token{}",Thread.currentThread().getId(),authorization);
        if(StringUtils.isNotBlank(authorization)){
            AsyncRequestContext.asyncToken.set(authorization);
        }
    }

    public  static  void removeAsyncToken(){
        log.info("Ansy Thread ID{}, Thread Token{}",Thread.currentThread().getId(),AsyncRequestContext.asyncToken.get());
        AsyncRequestContext.asyncToken.remove();

    }

    public  static String getAnsyToken(){
     String  authorization=  AsyncRequestContext.asyncToken.get();
        log.info("Thread ID{},ansy authorization{}",Thread.currentThread().getId(),authorization);
        return authorization;
    }
}

线程池中变量的传递

异步线程,主线程的变量变量会随着主线程的结束而变量销毁,如果将主线程的变量存在ThreadLocal中或者InheritableThreadLocal,存在ThreadLocal或InheritableThreadLocal者中存的线程变量会随着主线程的生命周期而销毁。在子线程中调用get()方法得不到主线程存储的值;
因此子线程中显示传递

在这里插入图片描述
在子线程中塞入ThreadLocal 中,在子线程中需要的时候在从ThreadLocal中随时获取,在线程池中还需要线程执行完毕remove()掉

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ThreadLocal 是 Java 中的一个类,用于实现线程本地存储。它可以让你在每个线程中存储一些数据,这些数据对于其它线程而言是不可见的,每个线程都可以独立地操作自己的数据,互不干扰。ThreadLocal 主要用于解决多线程并发访问共享变量的问题。 ThreadLocal使用方法很简单,只需要创建一个 ThreadLocal 对象,然后调用它的 set()、get() 方法即可。例如: ``` ThreadLocal<String> threadLocal = new ThreadLocal<>(); threadLocal.set("Hello World"); String value = threadLocal.get(); ``` 这段代码创建了一个 ThreadLocal 对象,然后存储了一个字符串 "Hello World" 到当前线程的 ThreadLocal 中,最后又取出了这个字符串。 但是,使用 ThreadLocal 也会存在一些问题。其中最常见的问题就是内存泄漏。由于 ThreadLocal 存储的数据是线程本地的,因此如果线程池中的线程没有及时地清理 ThreadLocal 中的数据,就会导致内存泄漏。解决这个问题的方法是在使用ThreadLocal 后及时调用 remove() 方法来清理数据。 还有一个问题是线程复用。在线程池中,线程可能会被重复使用,如果使用ThreadLocal,那么在下一次使用时,ThreadLocal 中的数据可能会残留上一次使用的数据,导致错误。解决这个问题的方法是在使用ThreadLocal 后及时调用 remove() 方法来清理数据,或者使用 InheritableThreadLocal,它可以让子线程继承父线程的 ThreadLocal 数据。 总之,ThreadLocal使用需要注意内存泄漏和线程复用等问题,正确使用可以有效地解决多线程并发访问共享变量的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值