zoukankan      html  css  js  c++  java
  • 多线程 ThreadLocal

    要了解ThreadLocal,首先搞清楚ThreadLocal 是什么?是用来解决什么问题的?

    ThreadLocal 是线程的局部变量, 是每一个线程所单独持有的,其他线程不能对其进行访问, 通常是类中的 private static 字段,是对该字段初始值的一个拷贝,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联

    我们知道有时候一个对象的变量会被多个线程所访问,这时就会有线程安全问题,当然我们可以使用synchorinized 关键字来为此变量加锁,进行同步处理,从而限制只能有一个线程来使用此变量,但是加锁会大大影响程序执行效率,此外我们还可以使用ThreadLocal来解决对某一个变量的访问冲突问题。

    当使用ThreadLocal维护变量的时候 为每一个使用该变量的线程提供一个独立的变量副本,即每个线程内部都会有一个该变量,这样同时多个线程访问该变量并不会彼此相互影响,因此他们使用的都是自己从内存中拷贝过来的变量的副本, 这样就不存在线程安全问题,也不会影响程序的执行性能。

    但是要注意,虽然ThreadLocal能够解决上面说的问题,但是由于在每个线程中都创建了副本,所以要考虑它对资源的消耗,比如内存的占用会比不使用ThreadLocal要大。

    ThreadLocal 方法使用详解

    ThreadLocal 的几个方法: ThreadLocal 可以存储任何类型的变量对象, get返回的是一个Object对象,但是我们可以通过泛型来制定存储对象的类型。

    public T get() { } // 用来获取ThreadLocal在当前线程中保存的变量副本
    public void set(T value) { } //set()用来设置当前线程中变量的副本
    public void remove() { } //remove()用来移除当前线程中变量的副本
    protected T initialValue() { } //initialValue()是一个protected方法,一般是用来在使用时进行重写的

    Thread 在内部是通过ThreadLocalMap来维护ThreadLocal变量表, 在Thread类中有一个threadLocals 变量,是ThreadLocalMap类型的,它就是为每一个线程来存储自身的ThreadLocal变量的, ThreadLocalMap是ThreadLocal类的一个内部类,这个Map里面的最小的存储单位是一个Entry, 它使用ThreadLocal作为key, 变量作为 value,这是因为在每一个线程里面,可能存在着多个ThreadLocal变量

    初始时,在Thread里面,threadLocals为空,当通过ThreadLocal变量调用get()方法或者set()方法,就会对Thread类中的threadLocals进行初始化,并且以当前ThreadLocal变量为键值,以ThreadLocal要保存的副本变量为value,存到threadLocals。 
    然后在当前线程里面,如果要使用副本变量,就可以通过get方法在threadLocals里面查找

    ThreadLocal是如何为每一个线程创建一个变量副本的,下面举一个例子来看一看。例子来源于 博客http://www.cnblogs.com/dolphin0520/p/3920407.html

    public class ThreadLocalTest {
        public static void main(String[] args) throws InterruptedException {
            final ThreadLocalTest test = new ThreadLocalTest();
    
            test.set();
            System.out.println(test.getLong());
            System.out.println(test.getString());
            // 在这里新建了一个线程
            Thread thread1 = new Thread() {
                public void run() {
                    test.set(); // 当这里调用了set方法,进一步调用了ThreadLocal的set方法是,会将ThreadLocal变量存储到该线程的ThreadLocalMap类型的成员变量threadLocals中,注意的是这个threadLocals变量是Thread线程的一个变量,而不是ThreadLocal类的变量。
                    System.out.println(test.getLong());
                    System.out.println(test.getString());
                };
            };
            thread1.start();
            thread1.join();
    
            System.out.println(test.getLong());
            System.out.println(test.getString());
        }
    
        ThreadLocal<Long> longLocal = new ThreadLocal<Long>();
        ThreadLocal<String> stringLocal = new ThreadLocal<String>();
    
        public void set() {
            longLocal.set(Thread.currentThread().getId());
            stringLocal.set(Thread.currentThread().getName());
        }
    
        public long getLong() {
            return longLocal.get();
        }
    
        public String getString() {
            return stringLocal.get();
        }
    
    }

    代码的输出结果: 

    main 

    Thread-0 

    main

    ThreadLocal 的应用场景

    最常见的ThreadLocal使用场景为 
    用来解决 数据库连接、Session管理等。

    数据库连接:

    Class A implements Runnable{
        private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() {
            public Connection initialValue() {
                    return DriverManager.getConnection(DB_URL);
            }
        };
    
        public static Connection getConnection() {
               return connectionHolder.get();
        }
    }

    Session管理

    private static final ThreadLocal threadSession = new ThreadLocal();
    
    public static Session getSession() throws InfrastructureException {
        Session s = (Session) threadSession.get();
        try {
            if (s == null) {
                s = getSessionFactory().openSession();
                threadSession.set(s);
            }
        } catch (HibernateException ex) {
            throw new InfrastructureException(ex);
        }
        return s;
    }
  • 相关阅读:
    设计模式 -- 桥接模式(Bridge)
    设计模式 -- 单例模式(Singleton)
    设计模式 -- 简单工厂模式
    Nginx服务器的启动控制
    【Vue.js】二、Vue的基础
    【Vue.js】一、Vue介绍和安装使用
    linux常用操作命令
    Redis的学习(一、Redis的一些常用技术)
    Spring的学习(四、Spring事务管理)
    Spring的学习(三、Spring中的AOP)
  • 原文地址:https://www.cnblogs.com/jtlgb/p/9485773.html
Copyright © 2011-2022 走看看