多线程学习 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

时间: 2024-08-12 09:06:41

多线程学习 ThreadLocal的使用。的相关文章

java多线程学习-ThreadLocal

为了凑字,把oracle文档里介绍ThreadLocal抄过来 public class ThreadLocal<T> extends Object This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its ow

Java多线程学习(吐血超详细总结)

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线程状态转换 五线程调度 六常用函数说明 使用方式 为什么要用join方法 七常见线程名词解释 八线程同步 九线程数据传递 本文主要讲了java中多线程的使用方法.线程同步.线程数据传递.线程状态及相应的一些线程函数用法.概述等. 首先讲一下进程和线程

Qt多线程学习:创建多线程

[为什么要用多线程?] 传统的图形用户界面应用程序都仅仅有一个运行线程,而且一次仅仅运行一个操作.假设用户从用户界面中调用一个比較耗时的操作,当该操作正在运行时,用户界面一般会冻结而不再响应.这个问题能够用事件处理和多线程来解决. [Linux有线程的概念吗?] 传统的UNIX系统也支持线程的概念,但一个进程里仅仅同意有一个线程,这样多线程就是多进程.Linux下的Posix线程(pthreads)是一种轻量级的进程的移植性实现,线程的调度由内核完毕,每一个线程都有自己的编号.假设使用线程,整体

Java多线程学习(详细)

一.进程与线程的区别 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程.(进程是资源分配的最小单位) 线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小.(线程是cpu调度的最小单位) 线程和进程一样分为五个阶段:创建.就绪.运行.阻塞.终止.     多进程是指操作系统能同时运行多个任务(程序).     多线程是指在同一程序中有多个顺序流在执行. 在java中要想实现多线程,有两种手段,一

C#多线程学习(一) 多线程的相关概念

什么是进程?    当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程所组成的. 什么是线程?    线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针.程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数. 什么是多线程?    多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务. 多线程的好处:    可以提

C#多线程学习(六) 互斥对象

C#多线程学习(六) 互斥对象 如何控制好多个线程相互之间的联系,不产生冲突和重复,这需要用到互斥对象,即:System.Threading 命名空间中的 Mutex 类. 我们可以把Mutex看作一个出租车,乘客看作线程.乘客首先等车,然后上车,最后下车.当一个乘客在车上时,其他乘客就只有等他下车以后才可以上车.而线程与Mutex对象的关系也正是如此,线程使用Mutex.WaitOne()方法等待Mutex对象被释放,如果它等待的Mutex对象被释放了,它就自动拥有这个对象,直到它调用Mute

C#多线程学习(一) 多线程的相关概念(转)

什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程所组成的. 什么是线程?线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针.程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数. 什么是多线程?多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务. 多线程的好处:可以提高CPU的利用率.在多线程程序中

多线程学习 + o2o简识

多线程学习: ( 1.NSThread 2.NSOperationQueue 3.GCD ) 1.进程和线程: 进程:app无法独立运行,需要分配内存空间,每个app至少有一个进程,是应用程序的开始(缺点:不能同时执行) 线程:是应用程序运行的最小单元可以多个线程并发同时执行,防止主线程堵塞,增加运行效率. 主线程:又叫UI主线程,程序运行都是在主线程加载,加载视图,但不可加载数据,因为请求网络数据的时间特别长,会出现空白现象(更新UI一定要在主线程中写) 子线程:没法加载UI,UI只在主线程中

java多线程学习(3)

1)竞争条件 在实际的多线程应用中,通常会有两个或多个线程需要对共同的对象进行共享访问,如果两个线程访问相同的对象,而且每一个都调用了一个会改变对象状态的方法, 那么,线程就会相互倾轧.根据各个线程访问数据的不同顺序,可能会产生腐蚀现象.这种情况通常称为竞争条件. 2)同步 为了多个线程对共享数据的腐蚀,就需要对数据的存取实现同步:常用的同步方法有3种: 1.Reenlock 用Reenlock保护代码块的基本机构如下: 1 Lock myLock=new ReenLock; 2 3 myLoc