`

ThreadLocal3

阅读更多

CurrentThread.map.set(currentThreadLocal, myobject);

 myobject =  (MyObject) CurrentThread.map.get(currentThreadLocal);

总之要ThreadLocal正常工作的话,必须要

每个Thread都有自己的myobject,否则还是不能正确实现的!!

和同步完全没有关系啊! 同步从同到尾巴,所有的线程只有一个object做为value

ThreadLocal是每个线程都有一个object做为value

ThreadUniqueID.Hashmap.put(ThreadLocal, new object in each Thread);

 

通常的HaspMap

Hashmap.put( String ,object);

Hashmap.put( Integer ,object);

这样的KEY(String ,Integer)在不同线程中HASH以后也都是一样的,所以会混乱.

ThreadLocal做的就是让这个map本身在不同线程下是不同,同一线程相同.

 

在所有线程中 从头到尾只有一个ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>()
   * Thread对象是JMV自动创建的
   * ThreadLocal保存所有的Treads ,每一个Thread对应一个haspMap(key:threadlocal本身,value:要保存的数据)
   *
   * 奇妙的就是ThreadLocal保存乐所有线程的信息,利用乐这些信息.
   * 当然只有我们调用get/set方法的时候才会去检查,如果ThreadLocal中没有当前Thread对应的map.就会 根据这个thread建立对应的map  (initValue -projected 方法,重写)

也可以说,1个ThreadLocal对象,当前有4个线程,则1个ThreadLocal对象维护(可以,不是一定(当线程调用GET/SET的时候,注意是线程调用.每个线程第一次调用,会产生对应的线程MAP))4个线程对应的map.

class ThreadLocal{

      Thread[]   //  JVM产生的线程数组而已 

}

class Thread{

        Map map (threadLocal,value);

}

 

我们可以用ThreadLocal保存Request,和同步没有任何关系,本身多线程下,每个请求都有不同的request对象!!

我们只是保存一下而已,方便取用.但是如果在DAO层等,用这种方法取用request,会让测试变的困难(需要虚拟request对象测试service ,dao....)

 

下面的代码乱写的,唉,水平太差

 

package a;

public class ThreadLocal5 {
	/*
	 * 这个相当于一个容器
	 */
	public static void main(String... args) {
		/*
		 * 一个容器只有一个Servlet实例 ServletServletTest 单实例多线程
		 */
		Servlet servletTest = new ServletTest();

		/*
		 * 多个线程调用同一个servlet
		 */
		for (int i = 0; i < 4; i++) {
			DummyThread dummyThread = new DummyThread(servletTest);
			Thread thread = new Thread(dummyThread);

			thread.start();
		}
	}
	
	/*
	 * 打印信息而已
	 */
	public static void logWithThreadInFor(Object o) {
		System.out.println(Thread.currentThread().getName() + " "
				+ (null == o ? "null" : o.toString()));

	}

}

/*
 * 更好的ServletTest可以实现一个接口 DummyThread.callServlet() 调用接口方法
 */
class ServletTest implements Servlet {
	
	

	/*
	 * servlet有一个dao实例变量 这个dao导致了多线程调用servlet不安全
	 * 
	 * 除去这个dao,servlet是线程安全的
	 */
	private DAOTest dao = new DAOTest();

	public void service() {
		/*
		 * 方法内部定义的dao,不存在线程同步问题.会有很多实例,创建很多DAO
		 */
		//DAOTest dao = new DAOTest();
		ThreadLocal5.logWithThreadInFor("Servlet: " + this.hashCode());
		ThreadLocal5.logWithThreadInFor(" Dao: " + dao.hashCode());
		/*
		 * 如果只有一个DAO,我们可以在DAO方法中每次都new Connection(),这样的话
		 * 同一个线程两个方法都是线程安全的,但是我们发现,在每一个线程中,DAO的不同方法,拿到的connection竟然是不同的,很郁闷
		 * 1个DAO = 多个线程  ; 每个线程 的每个DAO方法有一个CONNECTION
		 */
		dao.findUserIDByConnection(1);
		dao.findUserIDByConnection2(2);
	}

	// init()
	// destory()
	// service

	
}

/*
 * 这个DAOTest不是线程安全的 但是显然如果DAOTest的方法不调用任何实例变量,那么该方法是安全的
 */
class DAOTest {
	/*
	 * 这样定义Connection是不安全的
	 * 所有线程的Connection是一样的,同一个对象
	 */
	
	MultipleConnection conn=MultipleConnection.getConnection();
	
	/*
	 * 利用ThreadLocal,为每个线程建立一个Connection对象
	 */
	
	ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>(){
		/*
		 * 
		 * 每次返回的都是一个新的MultipleConnection.getConnection()
		 * 该方法在get的时候,如果ThreadLocal的map没有对应的值,就要执行
		 * 也就是说对每个线程只执行一次
		 * 不同线程得到不同的Connection,同个线程相同(DAO两个方法得到的CONNECTION是一样的)
		 * 
		 * 也就是我们说的,一个DAO = 多个线程 = 多个connection,每个线程只有一个connection
		 * 把不安全的DAO,变成安全的== 针对connection来说
		 * (如果还有其他的实例变量...又不安全了)
		 */
		
		@Override
		public MultipleConnection initialValue(){
			
			
			//ThreadLocal5.logWithThreadInFor(" intial value");
			return MultipleConnection.getConnection();
		}
		
		/*
		 * SingleConnection,单例模式
		 * 所以说尽管我用了ThreadLocal,其实没有用的!!
		 * 还是一个DAO = 多线程 = 一个connection
		 * 所有线程还是共享一个connection!!!
		 */
		
		/*@Override
		public SingleConnection initialValue(){
			
			
			//ThreadLocal5.logWithThreadInFor(" intial value");
			return SingleConnection.getConnection();
		}*/
	} ;

    public DAOTest(){
    	//ThreadLocal5.logWithThreadInFor("DAOTest Intial "); // main thread??
    	//intial();
    }
		
	private void intial(){
		this.threadLocal.set(MultipleConnection.getConnection());
	}
	
	/*
	 * 这个方法线程是安全的
	 */
	public int findUserID(int id) {
		return id;
	}

	public int findUserIDByConnection(int id) {
	
		
		/*
		 * 定义在这里,可以让conn变的线程安全
		 */
		//conn=Connection.getConnection();
		
		//
		ThreadLocal5.logWithThreadInFor(" Connection: "+id+" "+conn.hashCode());
		ThreadLocal5.logWithThreadInFor(" ThreadLocal Connection: "+"1"+" "+threadLocal.get().hashCode());
		ThreadLocal5.logWithThreadInFor(" ThreadLocal Object  =" +threadLocal);
		return id;
	}
	
	
	public int findUserIDByConnection2(int id) {
		/*
		 *定义在这里, 可以让conn变的线程安全
		 */
		//conn=Connection.getConnection();
		
		//
		ThreadLocal5.logWithThreadInFor(" Connection: "+id+" "+conn.hashCode());
		ThreadLocal5.logWithThreadInFor(" ThreadLocal Connection: "+"2"+" "+threadLocal.get().hashCode());
		
		/*
		 * 从头到尾只有一个ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>()
		 * Thread对象是JMV自动创建的
		 * ThreadLocal保存所有的Treads ,每一个Thread对应一个haspMap(key:threadlocal本身,value:要保存的数据)
		 * 
		 * 奇妙的就是ThreadLocal保存乐所有线程的信息,利用乐这些信息.
		 * 当然只有我们调用get/set方法的时候才会根据这个thread建立对应的map
		 * 
		 */
		ThreadLocal5.logWithThreadInFor(" ThreadLocal Object = " +threadLocal);
		return id;
	}
}

class DummyThread implements Runnable {

	private Servlet servletTest = null;

	public DummyThread(Servlet ServletTest) {
		this.servletTest = ServletTest;
	}

	public void run() {
		servletTest.service();
	}

}

interface Servlet {
	/*
	 * 可以传递过来request,response参数
	 */
	void service();
}

/* * 单例 这里仅仅是保证返回ServletTest 
 * 同时要把ServletTest的构造函数设置成私有. !!错误,这里怎么可以new呢?
 * 内部类实现吧,非本文重点
 * */
//==================

/*final class ServletManager {

	private static final Servlet servlet = new ServletTest();

	private ServletManager() {
	}

	public static Servlet getServlet() {
		return servlet;
	}
}*/

/*
 * 
 * 每次返回的都是一个新的Connection
 * 
 */

class MultipleConnection implements Connection{

	private MultipleConnection (){};
	public static MultipleConnection getConnection() {
		
		return new MultipleConnection();
	} 
} 


class SingleConnection implements Connection{
/*
 * 单例
 */
	private static SingleConnection singleConnection = new SingleConnection ();
	
	private SingleConnection(){};
	
	public static SingleConnection getConnection() {
		
		return singleConnection;
	} 
} 

interface Connection{
	 
}

 

0
0
分享到:
评论
1 楼 mercyblitz 2010-05-28  
Thread 没有生命周期时间,对于这种资源(需要关闭的),ThreadLocal还是会有问题。

相关推荐

Global site tag (gtag.js) - Google Analytics