线程上下文设计模式(上)

Posted Alleria Windrunner

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程上下文设计模式(上)相关的知识,希望对你有一定的参考价值。

什么是上下文

关于上下文(context),我们在开发的过程中经常会遇到,比如开发 struts2 的 ActionContext、Spring 中的 ApplicationContext,上下文是贯穿整个系统或阶段生命周期的对象,其中包含了系统全局的一些信息,比如登录之后的用户信息、账号信息,以及在程序每一个阶段运行时的数据。
在之前文章中定义的单例对象实际上也是上下文,并且它是贯穿整个程序运行的生命周期的上下文,比如以下代码就是典型的使用单例对象充当系统级别上下文的例子:
public final class ApplicationContext{ //在 Context 中保存 configuration 实例 private ApplicationConfiguration configuration; //在 Context 中保存 runtimeinfor 实例 private RuntimeInfo runtimeInfo; //...其他
//采用 Holder 的方式实现单例 private static class Holder{ private static ApplicationContext instance = new ApplicationContext(); }
public static ApplicationContext getContext(){ return Holder.instance; }
public void setConfiguration(ApplicationConfiguration configuration){ this.configuration = configuration; }
public ApplicationConfiguration getConfiguration(){ return this.configuration; }
public void setRuntimeInfo(RuntimeInfo runtimeInfo){ this.runtimeInfo = runtimeInfo; }
public RuntimeInfo getRuntimeInfo(){ return this.runtimeInfo; }}
在上面的代码中我们不难发现,如果 configuration 和 runtimeInfo 的生命周期会随着被创建一直到系统运行结束,我们就可以将 ApplicationContext 称为系统的上下文,诸如 configuration 和 runtimeInfo 等其他实例属性则称为系统上下文成员。
当然在设计系统上下文时,除了要考虑到它的全局唯一性(单例设计模式保证)之外,还要考虑到有些成员只能被初始化一次,比如配置信息的加载,以及在多线程环境下,上下文成员的线程安全性。


线程上下文设计

在有些时候,单个线程执行的任务步骤会非常多,后一个步骤的输入有可能是前一个步骤的输出,比如在单个线程多步骤(阶段)执行时,为了使得功能单一,有时候我们会采用 GoF 职责链设计模式,如下图所示。

虽然有些时候后一个步骤未必会需要前一个步骤的输出结果,但是都需要将 context 从头到尾进行传递,假如方法参数比较少还可以容忍,如果方法参数比较多,在七八次的调用甚至十几次的调用,都需要从头到尾地传递 context,很显然这是一种比较烦琐的设计,那么我们就可以尝试采用线程的上下文设计来解决这样的问题。
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;}
不同的线程访问 getActionContext()方法,每一个线程都将会获得不一样的 Action-Context 实例,原因是我们采用 Thread.currentThread()作为 contexts 的 key 值,这样就可以保证线程之间上下文的独立性,同时也不用考虑 ActionContext 的线程安全性(因为始终只有一个线程访问 ActionContext),因此线程上下文又被称为“线程级别的单例”。
注意,通过这种方式定义线程上下文很可能会导致内存泄漏,contexts 是一个 Map 的数据结构,用当前线程做 key,当线程的生命周期结束后,contexts 中的 Thread 实例不会被释放,与之对应的 Value 也不会被释放,时间长了就会导致内存泄漏(Memory Leak),当然可以通过 soft reference 或者 weak reference 等引用类型,JVM 会主动尝试回收。

以上是关于线程上下文设计模式(上)的主要内容,如果未能解决你的问题,请参考以下文章

在 recyclerview 片段中实现上下文操作模式的问题

多线程编程

onActivityResult 未在 Android API 23 的片段上调用

线程池

JUC并发编程 共享模式之工具 JUC CountdownLatch(倒计时锁) -- CountdownLatch应用(等待多个线程准备完毕( 可以覆盖上次的打印内)等待多个远程调用结束)(代码片段

python多线程