ThreadLocal(一) ThreadLocal使用场景和API介绍

其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是threadlocalvariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。

 

通俗的讲ThreadLocal本身就是一个Map,通过源码我们可以找到ThreadLocal里面有个内部类:

 /**
     * ThreadLocalMap is a customized hash map suitable only for
     * maintaining thread local values. No operations are exported
     * outside of the ThreadLocal class. The class is package private to
     * allow declaration of fields in class Thread.  To help deal with
     * very large and long-lived usages, the hash table entries use
     * WeakReferences for keys. However, since reference queues are not
     * used, stale entries are guaranteed to be removed only when
     * the table starts running out of space.
     */
    static class ThreadLocalMap {
        ......
    }

其实构造与hashMap差不多, 唯一的区别就是他的key 是其本身 ThreadLocal,可以通过它的set 方法看出来:

        /**
         * Set the value associated with key.
         *
         * @param key the thread local object
         * @param value the value to be set
         */
        private void set(ThreadLocal<?> key, Object value) {

            // We don't use a fast path as with get() because it is at
            // least as common to use set() to create new entries as
            // it is to replace existing ones, in which case, a fast
            // path would fail more often than not.
        
        .......
        
        }

每个线程调用全局的ThreadLocal对象的set方法, 就相当于往其内部的map增加一条记录, key分别是各自的线程, value是各自的set方法传进去的值, 在线程结束时可以调用ThreadLocal的clear方法, 这样会更快的释放内存(规范), 不调用也可以, 因为线程结束后也可以自动释放相关的ThreadLocal的变量(尽量不用, 因为ThreadLocal是弱引用, 可能会导致内容泄漏, 下面会写). 

下图是ThreadLocal的对象模型的

一 . ThreadLocal的使用场景:

1. 订单处理包含一系列操作:减少库存量, 增加一条流水台账, 修改总账, 这几个操作需要在同一个事务中完成, 通常也即是同一个线程中处理, 如果累加公司应收款操作失败了, 则应该把前面的操作回滚, 否则提交所有, 这要求这些操作使用相同的数据库连接对象, 而这些操作的代码应该分别位于不同的模块类中.

2.银行转账包含一系列操作, 把传出账户的余额减少,  把转入账户的余额增加, 这两个操作是要同一个事务中完成, 他们必须使用相同的数据库连接, 转入和转出操作的代码分别是两个人不同账户对象的方法.

总结: 一个ThreadLocal 代表一个变量, 故其中只能放一个数据, 如果你有两个变量要共享 , 可以定义一个对象里包含2个变量, 然后在ThreadLocal中存储这个变量, 一个标准的ThreadLocal封装类里(用private static 表示强引用,防止被gc回收), 必须有get方法, set方法, 在线程结束前, 必须调用thread的remove操作.

二、API说明

 

ThreadLocal()

          创建一个线程本地变量。

 

T get()

          返回此线程局部变量的当前线程副本中的值,如果这是线程第一次调用该方法,则创建并初始化此副本。

 

protected  T initialValue()

          返回此线程局部变量的当前线程的初始值。最多在每次访问线程来获得每个线程局部变量时调用此方法一次,即线程第一次使用 get() 方法访问变量的时候。如果线程先于 get 方法调用 set(T) 方法,则不会在线程中再调用 initialValue 方法。

 

   若该实现只返回 null;如果程序员希望将线程局部变量初始化为 null 以外的某个值,则必须为 ThreadLocal 创建子类,并重写此方法。通常,将使用匿名内部类。initialValue 的典型实现将调用一个适当的构造方法,并返回新构造的对象。

 

void remove()

          移除此线程局部变量的值。这可能有助于减少线程局部变量的存储需求。如果再次访问此线程局部变量,那么在默认情况下它将拥有其 initialValue。

 

void set(T value)

          将此线程局部变量的当前线程副本中的值设置为指定值。许多应用程序不需要这项功能,它们只依赖于 initialValue() 方法来设置线程局部变量的值。

 

在程序中一般都重写initialValue方法,以给定一个特定的初始值。

 

最后传送门: ThreadLocal 安全性和内存泄漏问题以及生产实例

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值