上下文设计模式

上下文定义:贯穿整个系统或阶段生命周期的对象,其中包含了系统全局的一些信息,比如登录之后的用户信息,账号信息,以及程序每一个阶段运行时的数据。

比如:单例模式的对象也就是上下文

private ConcurrentHashMap<Thread,ActionContext> contexts = new ConcurrentHashMap<>();



public ActionContext getActionContext(){

    ActionContext actionContext = contexts.get(Thread.currentThread());

    if(actionContext == null){

        actionContext = = new ActionContext();

        contexts.put(Thread.currentThread(),actionContext);

    }

    return actionContext;

}

因为currentThread始终唯一,所以线程上下文又被称为线程级别的单例。

注意:此种结构由于使用当前线程作为Key,当线程生命周期结束后,contexts中的Thread实例不会被释放。时间长了就会内存溢出。可以通过soft reference或weak reference引用

 

 

ThreadLocal使用场景及注意事项

1.在进行对象跨层传递时可以考虑使用ThreadLocal ,避免方法多次传递。打破层次间的约束

2.线程间的数据隔离

3.进行事务操作,用于存储线程事务信息

在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。

而ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。

ThreadLocal引用关系图

其中ThreadLocal与Entry中的key属于Weak Reference引用。当且仅当Entry中的key与ThreadLocal对象进行关联时,则ThreadLocal对象会在下一次GC时被回收。

一旦发生Full GC,如果线程已经不存在了。则会被自动回收。并且get()在遍历Entry时,如果发现key为null也会进行相应的回收。

ThreadLocal容易发生内存泄漏,尤其与线程池结合使用时,因为线程池中的Thread不会被回收,导致引用关系一直存在。所以需要尽量避免与线程池使用。一旦与线程池结合使用,退出时需要手动将    threadLocal = null;

 

另外ThreadLocal对象可以与多个ThreadLocalMap中的Entry建立关联。

public class Test {

    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();

    }

     

    public static void main(String[] args) throws InterruptedException {

        final Test test = new Test();

         

         

        test.set();

        System.out.println(test.getLong());

        System.out.println(test.getString());

     

         

        Thread thread1 = new Thread(){

            public void run() {

                test.set();

                System.out.println(test.getLong());

                System.out.println(test.getString());

            };

        };

        thread1.start();

        thread1.join();

         

        System.out.println(test.getLong());

        System.out.println(test.getString());

    }

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值