天天看点

ThreadLocal 读书笔记

1.ThreadLocal是什么?

从命名角度出发,可以理解为 thread local value(线程局部变量),即为每个线程提供局部变量。与同步机制共享一些变量不同,但是都是可以解决多线程并发的问题,只是二者面向的问题领域不同而已。

2.ThreadLocal实现机制?

查看java.lang.ThreadLocal源代码,我们可以知道其实是使用Map,存储每个线程的副本。

package java.lang;
import java.lang.ref.*;
import java.util.concurrent.atomic.AtomicInteger;

public class ThreadLocal<T> {
  
     ...

    //初始化变量,子类可重写此方法
    protected T initialValue() {
        return null;
    }

    //返回此线程局部变量的当前线程副本中的值。
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }

    //将此线程局部变量的当前线程副本中的值设置为指定值。
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
       
         //移除此线程局部变量当前线程的值。
     public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }
    ...
}
           

3.ThreadLocal 的使用

  • 结合单例模式,不同的线程调用get()获得自己的线程中的对象
import java.util.Vector;

public class SGThreadLocalContext {

	private static ThreadLocal<SGThreadLocalContext> threadLocals = new ThreadLocal<SGThreadLocalContext>();
	
	public static SGThreadLocalContext get() {
		SGThreadLocalContext context = threadLocals.get();
		if (context == null) {
			context = new SGThreadLocalContext();
			threadLocals.set(context);
		}
		return context;
	}

        //属性
	private String smallGroupAppID;	
	private String userContext;	
	
	public String getSmallGroupAppID() {return smallGroupAppID;}
	public void setSmallGroupAppID(String smallGroupAppID) {
		this.smallGroupAppID = smallGroupAppID;
	}	
	public String getUserContext() {return userContext;}
	public void setUserContext(String userContext) {
		this.userContext = userContext;
	}

}
           
  • Hibernate中,ThreadLocal管理多线程,保证每个线程都有自己的数据库连接
public static final ThreadLocal session = new ThreadLocal();
  public static Session currentSession() {
      Session s = (Session)session.get();
      //open a new session,if this session has none
   if(s == null){
      s = sessionFactory.openSession();
      session.set(s);
   }
      return s;
 } 
           
  • 日志程序,记录每个线程的活动
package thread;

import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

public class LoggerThreadTest {
	private static final ThreadLocal threadLocal = new ThreadLocal();

    public static void log(String msg) {
        getThreadLogger().log(Level.INFO, msg);
    }

    private static Logger getThreadLogger() {
        Logger logger = (Logger) threadLocal.get();

        if(logger == null) {
            try {
                logger = Logger.getLogger(Thread.currentThread().getName());
                // Logger 默认在控制台输出,添加文件输出处理器,输出XML格式
                logger.addHandler(
                    new FileHandler( Thread.currentThread().getName() + ".log")
                 );
            }catch(IOException e) {
            	e.printStackTrace();
            }

            threadLocal.set(logger);
        }

        return logger;
    }
	/**
	 * 测试日志
	 * @param args
	 */
	public static void main(String[] args) {
		new Test("thread1").start();
        new Test("thread2").start();
        new Test("thread3").start();

	}

}

class Test extends Thread {
    public Test(String name) {
        super(name);
    }

    public void run() {
        for(int i = 0; i < 10; i++) {
        	LoggerThreadTest.log(getName() + ": message " + i);
            try {
                Thread.sleep(1000);
            }
            catch(Exception e) {
            	LoggerThreadTest.log(e.toString());
            }
        }
    }
}