Java——ThreadLocal类

简介: 一,引入ThreadLocal/*测试ThreadLocal对象 * ThreadLocal:这个类提供了一个线程本地的变量。 * 这些变量在被共享访问的情况下在不同的线程里是独立的 ( 必须通过 get 和 set 方法来访问 ) 。



一,引入ThreadLocal


/*测试ThreadLocal对象
 * 	 ThreadLocal:这个类提供了一个线程本地的变量。
 * 			这些变量在被共享访问的情况下在不同的线程里是独立的 ( 必须通过 get 和 set 方法来访问 ) 。 
 *  很显然该类提供了一个机制可以防止多线程访问带来的不安全机制。实际上就是在线程本地保存一个变量,
 *  而不是通过共享变量。这个就要看我们的使用场合了,如果我们确实需要共享的数据,那还是必须通过同步机制来保证数据的安全。
 *  如果有些情况希望不同的线程保存的变量各自分开,那用这个还是比较合适的。

 ThreadLocal 这个类本身不是代表线程要访问的变量,这个类的成员变量才是。 
 JDK1.5 给 ThreadLocal 加了泛型功能,即是 ThreadLocal<T>, 这个泛型 T 即是要线程的本地变量。
 线程通过 ThreadLocal 的 get 和 set 方法去访问这个变量 T 。 ThreadLocal 提供了一个机制,
 它能保证线程通过这个来访问它来访问类型为 T 的变量的时候是不同的拷贝。所以访问该变量必须通过 Threadlocal 
 这个类只提供了两个 public 方法,即是 get() 和 set ()方法来访问。

 同时还提供了一个 inintValue() 的 protected 方法。该方法用来初始化变量值。

 注意 :默认情况下 initValue(), 返回 null 。线程在没有调用 set 之前,第一次调用 get 的时候,
 get 方法会默认去调用 initValue 这个方法。所以如果没有覆写这个方法,可能导致 get 返回的是 null 。
 当然如果调用过 set 就不会有这种情况了。但是往往在多线程情况下我们不能保证每个线程的在调用 get 之前都调用了 set ,
 所以最好对 initValue 进行覆写,以免导致空指针异常。 

 * */


       测试,在没有ThreadLocal的时候:


public class TestThreadLocal {
	public static int a = 0;
	

	public static void main(String[] args) {
		MyThread myThread=new MyThread();
		myThread.start();
		for(int i=0;i<5;i++){
			
			
			System.out.println(Thread.currentThread().getName()+":"+a);
			
		}
	}

	

	public static class MyThread extends Thread {
		public void run(){
			for(int i=0;i<5;i++){
				a=++a;
				
				System.out.println(Thread.currentThread().getName()+":"+a);
				
			}
		}
	}

}

  测试结果:


main:1
main:2
main:3
main:4
main:5
Thread-0:6
Thread-0:7
Thread-0:8
Thread-0:9
Thread-0:10

   发现结果很混乱,两个线程的执行明显有交叉。


   使用ThreadLocal之后:


public class TestThreadLocal {
	//public static int a = 0;
	public static ThreadLocal<Integer> a=new ThreadLocal<Integer>(){
		public Integer initialValue(){//初始化a的值
			return 0;
		}
	};

	public static void main(String[] args) {
		MyThread myThread=new MyThread();
		myThread.start();
		for(int i=0;i<5;i++){
			//a=++a;
			a.set(a.get()+1);
			System.out.println(Thread.currentThread().getName()+":"+a.get());
			
		}
	}

	

	public static class MyThread extends Thread {
		public void run(){
			for(int i=0;i<5;i++){
				//a=++a;
				a.set(a.get()+1);
				System.out.println(Thread.currentThread().getName()+":"+a.get());
				
			}
		}
	}

}

结果:


Thread-0:1
Thread-0:2
Thread-0:3
Thread-0:4
Thread-0:5
main:1
main:2
main:3
main:4
main:5

  使用了线程本地变量之后,我们必须通过get和set方法对变量进行读写。


二,简单介绍ThreadLocal

     

           

 /**
     * Returns the current thread's "initial value" for this
     * thread-local variable.  This method will be invoked the first
     * time a thread accesses the variable with the {@link #get}
     * method, unless the thread previously invoked the {@link #set}
     * method, in which case the <tt>initialValue</tt> method will not
     * be invoked for the thread.  Normally, this method is invoked at
     * most once per thread, but it may be invoked again in case of
     * subsequent invocations of {@link #remove} followed by {@link #get}.
     *
     * <p>This implementation simply returns <tt>null</tt>; if the
     * programmer desires thread-local variables to have an initial
     * value other than <tt>null</tt>, <tt>ThreadLocal</tt> must be
     * subclassed, and this method overridden.  Typically, an
     * anonymous inner class will be used.
     *
     * @return the initial value for this thread-local
     */
    protected T initialValue() {
        return null;
    }

    

        变量的初始化操作在这里完成,默认返回null,建议override此方法,确保get之前已进行过set操作,防止get的时候出错。


   

 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();
    }

      在ThreadLocal类中,有一个内部静态 类ThreadLocalMap,在这里存放着以key为当前threadLocal的object。


 
 public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }



     set方法也是这样类似的,ThreadLocal里面通常放入的值通常就是采用这两种方法进行操作的,哦,还有remove:


 

 public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

   好多代码のの。。。。大致先瞅瞅,然后接着切换回我们的spring源码解析,这篇只是小 插曲。







目录
相关文章
|
1天前
|
Java
【JAVA基础篇教学】第五篇:Java面向对象编程:类、对象、继承、多态
【JAVA基础篇教学】第五篇:Java面向对象编程:类、对象、继承、多态
|
1天前
|
存储 安全 Java
Java容器类List、ArrayList、Vector及map、HashTable、HashMap
Java容器类List、ArrayList、Vector及map、HashTable、HashMap
|
2天前
|
Java 编译器 开发者
Java一分钟之-继承:复用与扩展类的特性
【5月更文挑战第9天】本文探讨了Java中的继承机制,通过实例展示了如何使用`extends`创建子类继承父类的属性和方法。文章列举了常见问题和易错点,如构造器调用、方法覆盖、访问权限和类型转换,并提供了解决方案。建议深入理解继承原理,谨慎设计类结构,利用抽象类和接口以提高代码复用和扩展性。正确应用继承能构建更清晰、灵活的代码结构,提升面向对象设计能力。
9 0
|
2天前
|
Java
【Java多线程】面试常考 —— JUC(java.util.concurrent) 的常见类
【Java多线程】面试常考 —— JUC(java.util.concurrent) 的常见类
11 0
|
2天前
|
Java API 调度
【Java多线程】Thread类的基本用法
【Java多线程】Thread类的基本用法
6 0
|
2天前
|
SQL Java 数据库连接
JDBC Java标准库提供的一些api(类+方法) 统一各种数据库提供的api
JDBC Java标准库提供的一些api(类+方法) 统一各种数据库提供的api
9 0
|
3天前
|
Java
Java一分钟之-类与对象:面向对象编程入门
【5月更文挑战第8天】本文为Java面向对象编程的入门指南,介绍了类与对象的基础概念、常见问题及规避策略。文章通过代码示例展示了如何定义类,包括访问修饰符的适当使用、构造器的设计以及方法的封装。同时,讨论了对象创建与使用时可能遇到的内存泄漏、空指针异常和数据不一致等问题,并提供了相应的解决建议。学习OOP需注重理论与实践相结合,不断编写和优化代码。
26 1
|
4天前
|
Java 开发者
在Java中,接口和超类在多态性中扮演着重要的角色
Java中的接口和超类支持多态性,接口作为规范,允许多继承和回调机制;超类提供基类,实现代码重用和方法重写,两者共同促进代码的灵活性和可维护性。
26 10
|
4天前
|
Java
Java并发Futures和Callables类
Java程序`TestThread`演示了如何在多线程环境中使用`Futures`和`Callables`。它创建了一个单线程`ExecutorService`,然后提交两个`FactorialService`任务,分别计算10和20的阶乘。每个任务返回一个`Future`对象,通过`get`方法获取结果,该方法会阻塞直到计算完成。计算过程中模拟延迟以展示异步执行。最终,打印出10!和20!的结果。
|
9天前
|
网络协议 Java
Java中如何使用Socket类检测端口是否存在
Java中如何使用Socket类检测端口是否存在
24 4