多线程学习 ThreadLocal的使用。

  ThreadLocal ,即线程变量,是一个以ThreadLocal对象为键,任意对象为值得存储接口。这个接口被附带在线程上,也就是说一个线程可以根据一个ThreadLocal对象查询到绑定在这个线程上的值。

  可以通过set(T)方法来设置一个值,在当前线程下,在通过get()方法获取到原先设置的值。

  上面的文字是不是有点晦涩?来,学习一下明白的。

  变量值得共享可以使用 public static 变量的形式,所有的线程都使用同一个 public static 变量。如果想实现每一个线程都有自己的共享变量该如何解决那?

  jdk提供了ThreadLocal正是为了解决这样的问题。  

  类ThreadLocal 主要解决的就是每个线程绑定自己的值,可以将ThreadLocal类比喻成全局存放数据的盒子,盒子中可以存储每个线程的私有数据。

  

  下面实验:

  1 创建ThreadLocal对象,用来存储每个线程的私有值。

  

public class Tools {

	public static ThreadLocal t=new ThreadLocal();
}

  2 创建两个线程A,B.

  

public class ThreadA extends Thread {

	@Override
	public void run() {
		super.run();
		try {
			for(int i=0;i<100;i++){
				Tools.t.set("ThreadA "+(i+1));
				System.out.println("ThreadA get Value " + Tools.t.get());
				Thread.sleep(200);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

  

public class ThreadB extends Thread{

	@Override
	public void run() {
		super.run();
		try {
			for(int i=0;i<100;i++){
				Tools.t.set("ThreadB "+(i+1));
				System.out.println("ThreadB get Value "+Tools.t.get());
				Thread.sleep(200);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

  主线程:

public class Run {

	public static void main(String[] args) {
		
		try {
			ThreadA a=new ThreadA();
			ThreadB b=new ThreadB();
			a.start();
			b.start();
			
			for (int i = 0; i < 100; i++) {
				Tools.t.set("main "+(i+1));
				System.out.println("main get Value "+Tools.t.get());
				Thread.sleep(200);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}

  控制台:

ThreadB get Value ThreadB 1
ThreadA get Value ThreadA 1
main get Value main 1
ThreadA get Value ThreadA 2
main get Value main 2
ThreadB get Value ThreadB 2
main get Value main 3
ThreadA get Value ThreadA 3
ThreadB get Value ThreadB 3
ThreadA get Value ThreadA 4
ThreadB get Value ThreadB 4
main get Value main 4
ThreadB get Value ThreadB 5
ThreadA get Value ThreadA 5
main get Value main 5
main get Value main 6
ThreadB get Value ThreadB 6
ThreadA get Value ThreadA 6

  可以发现,ThreadA,ThreadB,和主线程三个在ThreadLocal中存储的值互不影响,每个线程增加,取值,都是自己的私有的。ThreadLocal中存储的值具有隔离性。

  使用类InheritableThreadLocal类可以让子线程中取得父线程中的值,并修改。

  下面使用ThreadLocal来模拟统计五个线程走完一段代码消耗的时间的问题。

  首先创建一个常用的Profiler类

  

public class Profiler {

	//第一次get()方法调用的时候会进行初始化(前提是set方法未调用),每个线程都会调用一次。
	private static final ThreadLocal<Long> TIME_THREADLOCAL=new ThreadLocal<Long>(){
		protected Long initialValue() {
			return System.currentTimeMillis();
		};
	};
	
	public static final void begin(){
		TIME_THREADLOCAL.set(System.currentTimeMillis());
	}
	
	public static final Long end(){
		return System.currentTimeMillis()-TIME_THREADLOCAL.get();
	}
}

    主线程中开启五个线程,并调用begin()和end()方法。(关于未调用set直接调用get返回是null的情况,注释已经解释解决办法。也可以通过继承ThreadLocal类,然后重写initialValue()方法改变初始化的值);

  

public class Run {

	public static void main(String[] args) {
		
		for (int i = 0; i < 5; i++) {
			final int temp=i;
			Thread thread=new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						Profiler.begin();
						Thread.sleep(temp*1000);
						System.out.println("线程"+Thread.currentThread().getName()+"消耗时间      "+Profiler.end());
					} catch (Exception e) {
						e.printStackTrace();
					}
					
				}
			});
			thread.start();
		}
		
		
	}
}

  控制台:

线程Thread-0消耗时间      0
线程Thread-1消耗时间      1000
线程Thread-2消耗时间      2000
线程Thread-3消耗时间      3001
线程Thread-4消耗时间      4001

  可以发现,五个线程互不影响,各自统计自己的消耗的时间。

  每一个优秀的人,都有一段沉默的时光。不抱怨,不诉苦,最后度过那段感动自己的日子。

  

原文地址:https://www.cnblogs.com/hrlizhi/p/9431880.html