`

Java ThreadLocal

 
阅读更多

 

ThreadLocal其实是个很常见的对象,可是你知道它的原理么?为何会设计ThreadLocal?

  参考了以下博客

         http://my.oschina.net/clopopo/blog/149368

         java特种兵

 

1.设计背景 下面一段网上摘录

   ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了线程保持对象的方法和避免参数传递的方便的对象访问方式 

   ThreadLocal的应用场合,最适合的是按线程多实例(每个线程对应一个实例)的对象的访问,并且这个对象很多地方都要用到。

   官方解释

   该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。 

 

2.ThreadLocal原理

    疑问一:ThreadLocal里面的map的键值是当前线程,这样如果有两个变量ThreadLocal<String> t1,ThreadLocal<String> t2 那么他们set的时候会冲掉之前的变量后来跟进代码发现原来不是这样的。 

   case如下

    

public class TestThreadLocal {
	
	public static ThreadLocal<String> resource1 = new ThreadLocal<String>();
	public static ThreadLocal<String> resource2 = new ThreadLocal<String>();
	
	public static void main(String[] args) {
		
		for(int i = 0; i< 10 ;i++){
			final int index = i;
			new Thread(new Runnable() {
				
				public void run() {
					// TODO Auto-generated method stub
					resource1.set(index+"----");
					resource2.set(index +"...");
					System.out.println(resource1.get()+"||||||"+resource2.get());
					resource1.remove();
					resource2.remove();
				}
			}).start();
		}
	}
	
}

     结果如下

     

0----||||||0...
3----||||||3...
2----||||||2...
1----||||||1...
4----||||||4...
5----||||||5...
7----||||||7...
6----||||||6...
8----||||||8...
9----||||||9...

     发现他们之间根本就是互不影响的,跟进ThreadLocal源码发现了错误在哪里了。

    

 /**
     * Sets the current thread's copy of this thread-local variable
     * to the specified value.  Most subclasses will have no need to 
     * override this method, relying solely on the {@link #initialValue}
     * method to set the values of thread-locals.
     *
     * @param value the value to be stored in the current thread's copy of
     *        this thread-local.
     * 
     */
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);  
        else
            createMap(t, value);
    }


 /**
     * Get the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param  t the current thread
     * @return the map
     */
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }


    /**
     * Create the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param t the current thread
     * @param firstValue value for the initial entry of the map
     * @param map the map to store.
     */
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

    

  可以发现这里的map确实是线程里面的。 

    结论:键值是this,这里的this应该是调用该方法的对象啊,所以是resource1或者ressource2

 

 

     疑问二,如果ThreadLocal存储的是对象呢,每个线程是一份拷贝呢,还是都是相同的对象呢?

     case

    

public class TestThreadLocal2 {
	public static ThreadLocal<Student> resource = new ThreadLocal<Student>();
	static class Student{
		String name ;
		
		public Student(String name){
			this.name = name;
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}
	}
	
	public static void main(String[] args) throws InterruptedException {
		final Student st = new Student("1111111");
		
		for(int i = 0; i< 10 ;i++){
			final int index = i;
			Thread.sleep(100);
			new Thread(new Runnable() {
				
				public void run() {
					// TODO Auto-generated method stub
					if(index %2 == 0){
						st.setName("1111"+index);
					}
					resource.set(st);
					System.out.println(st.hashCode()+","+resource.get().hashCode()+","+resource.get().getName());
					resource.remove();
				}
			}).start();
		}
	}

}

     输出结果如下:

     可以发现每个线程取出来的都是同一个hashCode,说明大家使用的是同一个对象,实际内存则存在堆中,如果这样使用的话应该还是存在可见性的问题。

    

1069480624,1069480624,11110
1069480624,1069480624,11110
1069480624,1069480624,11112
1069480624,1069480624,11112
1069480624,1069480624,11114
1069480624,1069480624,11114
1069480624,1069480624,11116
1069480624,1069480624,11116
1069480624,1069480624,11118
1069480624,1069480624,11118

 

     疑问三,比如某些场景如connection我想让每个线程使用自己的connection对象,不能让他们之间相互影响ThreadLocal就没有办法了吗? 当然是有的

    case 

    

public class TestThreadLocal2 {
	public static ThreadLocal<Student> resource = new ThreadLocal<Student>(){
		 protected Student initialValue() {
			 return new Student("111111111");
		 };
	};
	static class Student{
		String name ;
		
		public Student(String name){
			this.name = name;
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}
	}
	
	public static void main(String[] args) throws InterruptedException {
		final Student st = new Student("1111111");
		
		for(int i = 0; i< 10 ;i++){
			final int index = i;
			Thread.sleep(100);
			new Thread(new Runnable() {
				//这里没有set直接get了
				public void run() {
					System.out.println(st.hashCode()+","+resource.get().hashCode()+","+resource.get().getName());
					resource.remove();
				}
			}).start();
		}
	}

}

     结果如下

322722178,1595436971,111111111
322722178,616699029,111111111
322722178,482535999,111111111
322722178,16993205,111111111
322722178,1286693589,111111111
322722178,1535562945,111111111
322722178,729943514,111111111
322722178,646414701,111111111
322722178,2131949076,111111111
322722178,1018730552,111111111

      发现get出来的每个对象的hashCode都不相同。为何没有set直接get会有这种效果呢?

    

/**
     * Returns the value in the current thread's copy of this
     * thread-local variable.  If the variable has no value for the
     * current thread, it is first initialized to the value returned
     * by an invocation of the {@link #initialValue} method.
     *
     * @return the current thread's value of this thread-local
     */
    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();
    }

 

0
0
分享到:
评论

相关推荐

    java ThreadLocal多线程专属的变量源码

    java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多...

    Java ThreadLocal详解_动力节点Java学院整理

    Java ThreadLocal详解 ThreadLocal是Java中的一种机制,可以将变量与线程关联起来,使得每个线程都可以拥有自己的变量副本。 ThreadLocal的出现是为了解决多线程编程中的线程安全问题。 从本质上说,ThreadLocal是...

    JAVA ThreadLocal类深入

    【JAVA ThreadLocal类深入】 Java中的ThreadLocal类是一种线程绑定机制,用于在多线程环境中为每个线程提供独立的变量副本,避免了线程间的数据共享带来的并发访问问题。ThreadLocal并不是一个线程对象,而是线程...

    java 简单的ThreadLocal示例

    Java中的ThreadLocal是一个非常重要的工具类,它在多线程编程中扮演着独特角色,尤其在处理线程间数据隔离和共享时。ThreadLocal不是线程本身,而是为每个线程提供一个独立的变量副本,使得每个线程都可以独立地改变...

    Java ThreadLocal类应用实战案例分析

    Java ThreadLocal类应用实战案例分析 Java ThreadLocal类是Java语言中的一种线程局部变量机制,允许每个线程都拥有自己的变量副本,从而避免了多线程之间的变量冲突。在本文中,我们将通过实战案例分析Java ...

    java ThreadLocal使用案例详解

    Java ThreadLocal使用案例详解 Java ThreadLocal是Java语言中的一种机制,用于为每个线程提供一个独立的变量副本,以解决多线程环境下共享变量的线程安全问题。在本文中,我们将详细介绍Java ThreadLocal的使用案例...

    使用Java ThreadLocal.docx

    Java中的ThreadLocal是一个非常有用的工具类,它提供了一种线程局部变量的机制。线程局部变量(ThreadLocal)的特点是每个线程都有其独立的副本,这些副本之间互不干扰,即使它们共享同一个ThreadLocal实例。这使得...

    Java中ThreadLocal的设计与使用

    Java中的ThreadLocal是一个非常重要的工具类,它在多线程编程中扮演着独特角色,用于为每个线程提供独立的变量副本。理解ThreadLocal的工作原理和使用方法对于编写高效、安全的多线程程序至关重要。 ### ...

    java中ThreadLocal详解

    ### Java中ThreadLocal详解 #### 一、ThreadLocal概述 在Java多线程编程中,`ThreadLocal`是一个非常重要的工具类,它提供了一种在每个线程内部存储线程私有实例的方法。通常情况下,当多个线程共享某个变量时,...

    Java ThreadLocal用法实例详解

    Java ThreadLocal用法实例详解 Java ThreadLocal是Java中的一种线程局部变量机制,用于保存每个线程独有的数据,以避免线程之间的数据共享问题。ThreadLocal的基本使用非常简单,只需要定义一个ThreadLocal变量,...

    ThreadLocal应用示例及理解

    **线程局部变量(ThreadLocal)是Java编程中一个非常重要的工具类,它在多线程环境下提供了线程安全的数据存储。ThreadLocal并不是一个变量,而是一个类,它为每个线程都创建了一个独立的变量副本,使得每个线程都...

    深入浅出的学习Java ThreadLocal

    Java ThreadLocal 是一个非常重要的工具类,它提供了一种在多线程环境下为每个线程维护独立变量副本的机制。这种机制使得各个线程能够拥有自己的变量实例,而不会互相干扰,降低了数据共享的复杂性。 ### 应用场景 ...

    Java ThreadLocal的设计理念与作用

    主要介绍了Java ThreadLocal的设计理念与作用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    Spring定时任务中使用ThreadLocal的坑

    NULL 博文链接:https://bijian1013.iteye.com/blog/2380233

    入研究java.lang.ThreadLocal类.docx

    ### 知识点详解:Java.lang.ThreadLocal 类 #### 一、概述 **ThreadLocal** 并非线程的一种特殊实现形式,而是一种为每个线程提供独立副本的机制,通常被称为“线程局部变量”。这种机制使得每个线程都可以独立...

    彻底理解Java 中的ThreadLocal

    ThreadLocal是Java中一个非常重要的线程安全工具类,它为每个线程提供了一个独立的变量副本,使得每个线程可以独立地修改自己的副本,而不影响其他线程中对应的副本。这种机制使得线程间的变量隔离得以实现,有助于...

    java事务 - threadlocal

    Java事务和ThreadLocal是两种在Java编程中至关重要的概念,它们分别用于处理多线程环境下的数据一致性问题和提供线程局部变量。 首先,我们来深入理解Java事务。在数据库操作中,事务是一系列操作的集合,这些操作...

    简单分析Java线程编程中ThreadLocal类的使用共

    Java线程编程中的ThreadLocal类是一个非常重要的工具,它在多线程环境下提供了一种线程局部变量的机制。ThreadLocal并非是简单的变量,而是一种能够确保每个线程都拥有独立副本的变量容器。理解ThreadLocal的工作...

    java 中ThreadLocal 的正确用法

    java 中ThreadLocal 的正确用法 ThreadLocal 是 Java 中的一个特殊类,它可以让每个线程拥有自己独立的变量副本,避免了多线程之间的共享变量问题。下面我们将详细介绍 Java 中 ThreadLocal 的正确用法。 用法一...

    Java单线程ThreadLocal串值问题解决方案

    Java单线程ThreadLocal串值问题解决方案 Java单线程ThreadLocal串值问题解决方案主要介绍了Java单线程ThreadLocal串值问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值...

Global site tag (gtag.js) - Google Analytics