最近研究CAS,先从客户开始来说明CAS的逻辑,可能会结合源代码。
必要说明:http://blog.csdn.net/yuwenruli/article/details/6602180
言归正传,AssertionThreadLocalFilter作用很简单,就是将Assertion绑定到ThreadLocal,这样做有什么好处?
这个要从ThreadLocal对象的作用来说起了,
Why ThreadLocal?
无论如何,要编写一个多线程安全(Thread-safe)的程序是困难的,为了让线程共享资源,必须小心地对共享资源进行同步,同步带来一定的效能延迟,而另一方面,在处理同步的时候,又要注意对象的锁定与释放,避免产生死结,种种因素都使得编写多线程程序变得困难。
尝试从另一个角度来思考多线程共享资源的问题,既然共享资源这么困难,那么就干脆不要共享,何不为每个线程创造一个资源的复本。将每一个线程存取数据的行为加以隔离,实现的方法就是给予每个线程一个特定空间来保管该线程所独享的资源什么是ThreadLocal?
顾名思义它是local variable(线程局部变量)。它的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有该变量。
使用场景
ThreadLocal类
它主要由四个方法组成initialValue(),get(),set(T),remove(),其中值得注意的是initialValue(),该方法是一个protected的方法,显然是为了子类重写而特意实现的。该方法返回当前线程在该线程局部变量的初始值,这个方法是一个延迟调用方法,在一个线程第1次调用get()或者set(Object)时才执行,并且仅执行1次。ThreadLocal中的确实实现直接返回一个null:
ThreadLocal的原理
ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。比如下面的示例实现:
public class ThreadLocal
{
private Map values = Collections.synchronizedMap(new HashMap());
public Object get()
{
Thread curThread = Thread.currentThread();
Object o = values.get(curThread);
if (o == null && !values.containsKey(curThread))
{
o = initialValue();
values.put(curThread, o);
}
return o;
}
public void set(Object newValue)
{
values.put(Thread.currentThread(), newValue);
}
public Object initialValue()
{
return null;
}
}
好了,背景知识介绍完毕了,我们来看看AssertionThreadLocalFilter做了什么,上源码:
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException { //转换参数 final HttpServletRequest request = (HttpServletRequest) servletRequest; final HttpSession session = request.getSession(false); //取得Assertion对象,如果session为null则从request中取得,否则从session中取得。 final Assertion assertion = (Assertion) (session == null ? request.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION) : session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION)); try { //绑定到ThreadLocal AssertionHolder.setAssertion(assertion); // 处理后面的过滤器,这样后面的Fileter和Servlet可以在线程中取得Assertion对象。 filterChain.doFilter(servletRequest, servletResponse); } finally { //处理完毕后清理线程 AssertionHolder.clear(); } }
怎么样?是不是很简单?里面的AssertionHolder类持有一个ThreadLocal<Assertion>对象。有了这样的一个过滤器,我们后面的代码都可以直接使用了,怎么使用?看下面代码:
AssertionHolder.getAssertion()