Java并发编程:深入剖析ThreadLocal

一.什么是ThreadLocal

二.深入解析ThreadLocal

三.巧用ThreadLocal

 

  1. ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

     
  2. 深入源码一探究竟

    a.首先了解一下几个通用的方法

    public T get() { }

    public void set(T value) { }

    public void remove() { }

    protected T initialValue() { }   


    get()方法是用来获取ThreadLocal在当前线程中保存的变量副本,set()用来设置当前线程中变量的副本,remove()用来移除当前线程中变量的副本,initialValue()是一个protected方法,一般是用来在使用时进行重写的,在不调用set()方法的情况下,靠此方法初始化副本的变量

    b.首先我们先来看一下get方法的实现

        /**
         * Returns the value in the current thread's copy of this
         * thread-local variable.  If the variable has no value for the
         * current thread, it is first initialized to the value returned
         * by an invocation of the {@link #initialValue} method.
         *
         * @return the current thread's value of this thread-local
         */
        public T get() {
            Thread t = Thread.currentThread();
            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();
        }

           第一句是取得当前线程,然后通过getMap(t)方法获取到一个map,map的类型为ThreadLocalMap。然后接着下面获取到<key,value>键值对,注意这里获取键值对传进去的是  this,而不是当前线程t。如果map不为空,则返回value值。否则则调用setInitialValue方法返回value。
     
    b.再看一下getMap方法中做了什么:

        /**
         * Get the map associated with a ThreadLocal. Overridden in
         * InheritableThreadLocal.
         *
         * @param  t the current thread
         * @return the map
         */
        ThreadLocalMap getMap(Thread t) {
            return t.threadLocals;
        }

           在getMap中,是调用当期线程t,返回当前线程t中的一个成员变量threadLocals。

    c.那么我们继续取Thread类中取看一下成员变量threadLocals是什么:

        /* ThreadLocal values pertaining to this thread. This map is maintained
         * by the ThreadLocal class. */
        ThreadLocal.ThreadLocalMap threadLocals = null;

    实际上就是一个ThreadLocalMap,这个类型是ThreadLocal类的一个内部类.

    d.我们继续取看ThreadLocalMap的实现:

     

        static class ThreadLocalMap {
    
            /**
             * The entries in this hash map extend WeakReference, using
             * its main ref field as the key (which is always a
             * ThreadLocal object).  Note that null keys (i.e. entry.get()
             * == null) mean that the key is no longer referenced, so the
             * entry can be expunged from table.  Such entries are referred to
             * as "stale entries" in the code that follows.
             */
            static class Entry extends WeakReference<ThreadLocal<?>> {
                /** The value associated with this ThreadLocal. */
                Object value;
    
                Entry(ThreadLocal<?> k, Object v) {
                    super(k);
                    value = v;
                }
            }
    
            //此处省略部分。。。。。。。。。。
    }

    可以看到ThreadLocalMap的Entry继承了WeakReference,并且使用ThreadLocal作为键值。


    e.然后再继续看setInitialValue方法的具体实现:

        /**
         * Variant of set() to establish initialValue. Used instead
         * of set() in case user has overridden the set() method.
         *
         * @return the initial value
         */
        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;
        }

    T value = initialValue();一般我们会重写此方法,走到这里会调用我们自己写的initialValue();方法,该方法用于给线程副本初始化,在接着代码就是,如果map不为空,就设置键值对,如果为空,再创建Map.

    f.看一下createMap的实现:

        /**
         * Create the map associated with a ThreadLocal. Overridden in
         * InheritableThreadLocal.
         *
         * @param t the current thread
         * @param firstValue value for the initial entry of the map
         */
        void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }

      createMap()就是为接上面map为空的情况下,来为ThreadLocalMap初始化的


          g.至此,可能大部分朋友已经明白了ThreadLocal是如何为每个线程创建变量的副本的,再总结一下,首先,在每个线程Thread内部有一个ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,这个threadLocals就是用来存储实际的变量副本的,键值为当前ThreadLocal变量,value为变量副本(即T类型的变量)。初始时,在Thread里面,threadLocals为空,当通过ThreadLocal变量调用get()方法或者set()方法,就会对Thread类中的threadLocals进行初始化,并且以当前ThreadLocal变量为键值,以ThreadLocal要保存的副本变量为value,存到threadLocals。然后在当前线程里面,如果要使用副本变量,就可以通过get方法在threadLocals里面查找。

  3. 巧用threadLocals
           利用threadLocals我们可以将数据库连接对象,或者一些上下文对象,保存在当前每个线程副本中。这样我们就不用在将这个变量用于参数传递,并且在每个线程中都可以获取,并且互不影响的,大大简化了操作,下面就医数据库连接对象为例,贴出代码实现。

     

    import java.sql.Connection;
    import java.sql.SQLException;
    
    import javax.sql.DataSource;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    /**
     * 等效 JdbcUtils,用于提供获得连接工具类
     */
    public class C3P0Utils {
    	
    	//连接池
    	private static ComboPooledDataSource dataSource = new ComboPooledDataSource("test"); 
    	
    	//提供ThreadLocal用于为不同线程缓存连接
    	private static ThreadLocal<Connection> local = new ThreadLocal<Connection>();
    	
    	/**
    	 * 获得数据源(连接池)
    	 * @return
    	 */
    	public static DataSource getDataSource(){
    		return dataSource;
    	}
    	
    	/**
    	 * 获得连接
    	 * @return
    	 * @throws SQLException 
    	 */
    	public static Connection getConnection() throws SQLException{
    		//1 从本地线程变量获得
    		Connection conn = local.get();
    		
    		//2 如果没有,从连接池获得,并添加到ThreadLocal中
    		if(conn == null){
    			//将从连接池中获得连接
    			conn = dataSource.getConnection();
    			//需保持本地
    			local.set(conn);
    		}
    		
    		//3 返回连接
    		return conn;
    	}
    }
    

     

【EI复现】基于元模型优化算法的主从博弈多虚拟电厂动态定价和能量管理(Matlab代码实现)内容概要:本文介绍了基于元模型优化算法的主从博弈多虚拟电厂动态定价与能量管理的研究,结合Kriging模型与多目标遗传算法(NSGA2)实现最优变量求解,旨在提升多虚拟电厂系统在复杂电力市场环境下的调度效率与经济效益。研究通过Matlab代码实现,构建了主从博弈框架,其中上级为电网或运营商,下级为多个虚拟电厂,通过动态定价机制引导各虚拟电厂优化自身能量管理策略,兼顾供需平衡、成本控制与可再生能源消纳。该方法有效解决了高维非线性优化问题,提升了求解精度与收敛速度,适用于多目标、多约束的能源系统优化场景。; 适合人群:具备一定电力系统、优化算法与Matlab编程基础的研究生、科研人员及从事能源管理、智能电网相关工作的技术人员;尤其适合致力于虚拟电厂、需求响应、博弈论应用等领域研究的专业人士。; 使用场景及目标:①应用于多虚拟电厂协同调度与市场竞价策略设计;②实现动态电价机制下的用户侧响应优化;③为含高比例可再生能源的配电网提供能量管理解决方案;④支持科研复现EI/SCI级别论文中的主从博弈与元模型优化方法。; 阅读建议:建议读者结合提供的Matlab代码与网盘资料,重点理解Kriging代理模型的构建过程、NSGA2算法的集成方式以及主从博弈的数学建模思路,通过调试与仿真逐步掌握算法参数设置与性能评估方法,进而拓展至其他复杂能源系统优化问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值