zoukankan      html  css  js  c++  java
  • ThreadLocal(线程的局部变量)

    1.ThreadLocal是Java1.2提出来的一种对线程的所在执行的线程栈的局部变量

    这个方式打印出来的就可以说明一个问题,不同的线程他们的的线程栈是不一样的,换句话当同一个方法被同一个不同的线程调用的时候,他们都会进入各自的线程之间的

    栈内存之中。

    public class Main {
        public static void main(String[] args) throws Exception {
            log("start main...");
            new Thread(() -> {
                log("run task...");
            }).start();
            new Thread(() -> {
                log("print...");
            }).start();
            log("end main.");
        }
    
        static void log(String s) {
            System.out.println(Thread.currentThread().getName() + ": " + s);
        }
    }

     现象:

    main: start main...
    Thread-0: run task...
    main: end main.
    Thread-1: print...

     2.ThreadLocal可以避免在同一个线程之间同一个参数的在不同地方调用(前提是同一个线程),这样可以避免了同一个参数在同一个线程执行中的多次传递;ThreadLocal实例通常总是以静态字段初始化如下:

    static ThreadLocal<User> threadLocalUser = new ThreadLocal<>();

    它的典型使用方式如下:

    void processUser(user) {
        try {
            threadLocalUser.set(user);
            step1();
            step2();
        } finally {
            threadLocalUser.remove();
        }

    通过设置一个User实例关联到ThreadLocal中,在移除之前,所有方法都可以随时获取到该User实例:

    void step1() {
        User u = threadLocalUser.get();
        log();
        printUser();
    }
    
    void log() {
        User u = threadLocalUser.get();
        println(u.name);
    }
    
    void step2() {
        User u = threadLocalUser.get();
        checkUser(u.id);
    }

    注意到普通的方法调用一定是同一个线程执行的,所以,step1()step2()以及log()方法内,threadLocalUser.get()获取的User对象是同一个实例。

    实际上,可以把ThreadLocal看成一个全局Map<Thread, Object>:每个线程获取ThreadLocal变量时,总是使用Thread自身作为key:

    Object threadLocalValue = threadLocalMap.get(Thread.currentThread());

     因此,ThreadLocal相当于给每个线程都开辟了一个独立的存储空间,各个线程的ThreadLocal关联的实例互不干扰。最后,特别注意ThreadLocal一定要在finally中清除:

    try {
        threadLocalUser.set(user);
        ...
    } finally {
        threadLocalUser.remove();
    }

     这是因为当前线程执行完相关代码后,很可能会被重新放入线程池中,如果ThreadLocal没有被清除,该线程执行其他代码时,会把上一次的状态带进去。为了保证能释放ThreadLocal关联的实例,我们可以通过AutoCloseable接口配合try (resource) {...}结构,让编译器自动为我们关闭。例如,一个保存了当前用户名的ThreadLocal可以封装为一个UserContext对象:

    public class UserContext implements AutoCloseable {
    
        static final ThreadLocal<String> ctx = new ThreadLocal<>();
    
        public UserContext(String user) {
            ctx.set(user);
        }
    
        public static String currentUser() {
            return ctx.get();
        }
    
        @Override
        public void close() {
            ctx.remove();
        }
    }

     

    有志者、事竟成,破釜沉舟,百二秦关终属楚; 苦心人、天不负,卧薪尝胆,三千越甲可吞吴. 加油吧,致每个正在奋斗路上的你!!!
  • 相关阅读:
    廖雪峰的多线程 1
    保持良好的心态 戒骄戒躁
    Break camelCase
    int32 to IPv4 (int32到IPv4地址转换)
    Stop gninnipS My sdroW!
    Find The Parity Outlier 找到奇偶校验异常值
    今日新闻整理 2020-7-31
    改造rabbitmq demo 到 jpa
    Flink实战(110):FLINK-SQL应用场景(11)connector(十九)Flink 与 hive 结合使用(七) Flink Hive Connector 使用
    Hadoop基础(六十):面试题 Hadoop数据切片(二)切片机制源码
  • 原文地址:https://www.cnblogs.com/cb1186512739/p/14214176.html
Copyright © 2011-2022 走看看