美文网首页
JUC 之 ThreadLocal 的运用

JUC 之 ThreadLocal 的运用

作者: Tinyspot | 来源:发表于2023-10-23 09:54 被阅读0次

1. 会话管理器

/**
 * 会话管理器
 */
@Slf4j
public class SessionFactory {
    private static ThreadLocal<SessionContext> threadLocal = new ThreadLocal<>();
    
    public static SessionContext getSession() {
        return threadLocal.get();
    }

    public static SessionContext createSession(String entryName, String id) {
        if(threadLocal.get() == null){
            try {
                threadLocal.set(new SessionContext(entryName, id));
            } catch (Exception e) {
            }
        }
        log.info("threadLocal.get(): " + threadLocal.get());
        return threadLocal.get();
    }

    /**
     * 谁创建谁销毁
     */
    public static void destroySession(String entryName) {
        if (threadLocal.get() == null) {
            return;
        }
        if(entryName != null && entryName.equals(threadLocal.get().getEntryName())) {
            threadLocal.set(null);
        } else if (threadLocal.get().getEntryName() == null) {
            threadLocal.set(null);
        }
    }
}
/**
 * 会话上下文
 */
@Data
public class SessionContext implements Serializable {
    private static final long serialVersionUID = -5118360132451003980L;

    /**
     * 会话Id
     */
    private String id;
    /**
     * 会话入口方法
     */
    private Method entrydMethod;
    /**
     * 会话入口名称
     */
    private String entryName;

    private String identityCode;
    private String sceneCode;
    /**
     * 会话属性
     */
    private Map<String, Object> attributeMap = new HashMap<>();

    public SessionContext() {
        this.id = UUID.randomUUID().toString().replaceAll("-", "");
    }

    public SessionContext(String entryName, String id) {
        if (StringUtils.isNotBlank(id)) {
            this.id = id;
        } else {
            this.id = UUID.randomUUID().toString().replaceAll("-", "");
        }
        this.entryName = entryName;
    }

    public void setAttribute(String name, Object value) {
        attributeMap.put(name, value);
    }

    public void removeAttribute(String name) {
        attributeMap.remove(name);
    }
}

2. 工具类

2.1 SessionUtil

public class SessionUtil {

    public static void setIdentityCode(String identityCode) {
        SessionContext session = SessionFactory.getSession();
        if(session != null) {
            session.setIdentityCode(identityCode);
        }
    }

    public static void setSceneCode(String sceneCode) {
        SessionContext session = SessionFactory.getSession();
        if(session != null) {
            session.setSceneCode(sceneCode);
        }
    }

    /**
     * session属性值
     */
    public static void setAttributes(OrderDTO orderDTO) {
        if (orderDTO == null) {
            return;
        }
        setTradeId(orderDTO.getTradeId());
        // other...
    }

    public static void setTradeId(String tradeId) {
        setAttribute("tradeId", tradeId);
    }

    public static void setAttribute(String key, Object value) {
        if(key != null && value != null) {
            SessionContext session = SessionFactory.getSession();
            if(session != null) {
                session.setAttribute(key, value);
            }
        }
    }
}

2.2 LocalSessionUtil

public class LocalSessionUtil {

    /**
     * 内部通用会话id
     */
    public static String getInnerSessionId() {
        String remoteSessionId = LocalSessionUtil.getRemoteSessionId();
        if (StringUtils.isNotBlank(remoteSessionId)) {
            return remoteSessionId;
        }
        return initLocalSessionId();
    }

    /**
     * 获取 RPC 的 session id
     */
    public static String getRemoteSessionId() {
        // todo
        return "";
    }

    /**
     * 生成随机 sessionId
     *
     *  ip           +   毫秒数   +   随机UUID
     *  8位(16进制)       取6位       取10位
     */
    public static String initLocalSessionId() {
        return IpUtils.getHexIp()
                + getMilliseconds()
                + generatorId(10);
    }
    
    public static String getGeneratorId() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }
    
    private static String generatorId(int length) {
        return getGeneratorId().substring(0, length);
    }

    private static String getMilliseconds() {
        long nowTime = System.currentTimeMillis();
        return String.valueOf(nowTime % 1000000L);
    }
}

2.3 IpUtils

import java.net.InetAddress;

public class IpUtils {
    private static final String IP_SPLIT_TAG = "\\.";

    private static String cacheIp = null;

    public static String getLocalIp() {
        try {
            if(cacheIp == null) {
                cacheIp = InetAddress.getLocalHost().getHostAddress();
            }
        } catch (Throwable t) {
            cacheIp = "unknown_ip";
        }
        return cacheIp;
    }

    /**
     * 返回十六进制的IP
     * @return
     */
    public static String getHexIp() {
        StringBuilder builder = new StringBuilder();

        String[] ipSplits = IpUtils.getLocalIp().split(IP_SPLIT_TAG);
        for (String segment : ipSplits) {
            String hex = Integer.toHexString(Integer.parseInt(segment));
            // ip为个位数时,手动补0
            if (hex.length() < 2) {
                builder.append("0");
            }
            builder.append(hex);
        }
        return builder.toString();
    }
}

3. 调用示例

3.1 ThreadLocalController

调用地址 http://localhost:8080/thread/threadLocal

@RestController
@RequestMapping("/thread")
public class ThreadLocalController {
    private static Logger logger = LoggerFactory.getLogger(ThreadLocalController.class);

    @Resource
    private SceneTemplate sceneTemplate;

    @RequestMapping("/threadLocal")
    public String threadLocal() {

        SingleResultDTO<OrderDTO> result = sceneTemplate.execute(new SceneCallback<OrderDTO>() {
            @Override
            public String getIdentityCode() {
                return "local";
            }

            @Override
            public String getSceneCode() {
                return "threadLocal";
            }

            @Override
            public SingleResultDTO<OrderDTO> executeScene(String identityCode, String sceneCode) {
                SingleResultDTO<OrderDTO> resultDTO = SingleResultDTO.successResult(new OrderDTO("1001", "20201010"));
                return resultDTO;
            }
        }, logger);

        return JSON.toJSONString(result);
    }
}

3.2 模板

public interface SceneTemplate<R> {
    SingleResultDTO<R> execute(SceneCallback<R> action, Logger logger);
}
public interface SceneCallback<R> {
    String getIdentityCode();
    String getSceneCode();
    SingleResultDTO<R> executeScene(String identityCode, String sceneCode);
}
@Data
public class SingleResultDTO<T> implements Serializable {
    private static final long serialVersionUID = -1599951090724597173L;

    private T result;
    private String errorCode;
    private String errorDesc;
    private Boolean success;

    public static <T> SingleResultDTO<T> successResult(T data) {
        SingleResultDTO<T> result = new SingleResultDTO<T>();
        result.setResult(data);
        result.setSuccess(true);
        return result;
    }
}

3.3 SceneTemplateImpl

@Component
@Slf4j
public class SceneTemplateImpl<R> implements SceneTemplate<R> {

    @Override
    public SingleResultDTO<R> execute(SceneCallback<R> action, Logger logger) {
        SingleResultDTO<R> result = new SingleResultDTO<>();
        StringBuilder builder = new StringBuilder();

        long startTime = System.currentTimeMillis();

        String identityCode = null;
        String sceneCode = null;
        String sessionEntryName = null;
        try {
            // do something...
            identityCode = action.getIdentityCode();
            sceneCode = action.getSceneCode();

            // 初始化session
            if (Objects.isNull(SessionFactory.getSession())) {
                // 暂定用 UUID 作为会话名称
                // sessionEntryName = Thread.currentThread().getName() + "@" + LocalSessionUtil.getGeneratorId();
                sessionEntryName = LocalSessionUtil.getGeneratorId();
                SessionFactory.createSession(sessionEntryName, LocalSessionUtil.getInnerSessionId());
            }
            SessionUtil.setIdentityCode(identityCode);
            SessionUtil.setSceneCode(sceneCode);

            // 正式执行
            result = action.executeScene(identityCode, sceneCode);

            builder.append(identityCode).append("#").append(sceneCode).append("#");
            long duration = System.currentTimeMillis() - startTime;
            builder.append(duration).append("ms");
            logger.info(builder.toString());

        } catch (Throwable e) {
            long duration = System.currentTimeMillis() - startTime;
            builder.append(duration).append("ms");
            logger.error(builder.toString());

        } finally {
            // do something...

            if (StringUtils.isNotBlank(sessionEntryName)) {
                SessionFactory.destroySession(sessionEntryName);
            }
        }

        return result;
    }
}

相关文章

  • juc之五: ThreadLocal

    1. ThreadLocal (JDK版本) 1.1 ThreadLocal 概述 1.2 Thread-Thre...

  • JUC-ThreadLocal

    一、ThreadLocal   把ThreadLocal看成一个全局Map ,每个线程获取ThreadLocal变...

  • ThreadLocal的使用事例

    列举几个使用ThreadLocal的事例,能更好的理解ThreadLocal。 1、运用ThreadLocal实现...

  • Java多线程相关知识点汇总

    1.ThreadLocal2.如何保证高并发场景下的线程安全?3.JUC(java.util.concurrent...

  • ThreadLocal源码解析与运用(下)

    ThreadLocal在框架中的运用 ThreadLocal在JAVA框架中得到了大量的运用,甚至上升为一种设计模...

  • ThreadLocal

        ThreadLocal不是JUC并发包下工具,它在java.lang包下面。多线程访问同一个共享变量的时候...

  • JUC知识点总结

    作为并发的基础,我们需要熟悉掌握JUC相关的知识,才能更好的在实际项目中运用,下面是整理出来的juc思维导图: 系...

  • JAVA基础—JUC包(java.util.concurrent

    1. JUC - CountDownLatch 倒计时锁 运行结果 2. JUC之Semaphore信号量 运行结...

  • JUC源码循序渐进

    目录 必读篇 JUC源码分析—CAS和Unsafe JUC源码分析—AQS JUC锁篇 JUC源码分析-JUC锁(...

  • 2018-07-26 CountDownLatch

    【转】Java多线程系列--“JUC锁”09之 CountDownLatch原理和示例

网友评论

      本文标题:JUC 之 ThreadLocal 的运用

      本文链接:https://www.haomeiwen.com/subject/rpadidtx.html