ThreadLocal
来源:互联网 发布:关于农副产品的软件 编辑:程序博客网 时间:2024/04/27 13:06
ThredLocal不是一个线程,而是一个线程的本地化对象,当工作于多线程的对象用ThreadLocal维护变量(即共享资源)时,ThreadLocal会为每个使用该变量(即访问共享资源)的线程创建一个变量副本,每个线程操作的是ThreadLocal提供的变量副本,不会影响到其他线程,从而解决了共享资源在并发访问时带来的线程安全问题;
这个变量副本从线程的角度来说,就像是线程的一个本地变量或叫局部变量;
ThreadLocal的接口方法:
1 public void set(Object value);
设置当前线程的线程局部变量的值
2 public Object get();
返回当前线程的线程局部变量的值
3 public void remove();
将当前线程的线程局部变量的值删除,目的是较少内存占用
4 protected Object initialValue();
获取当前线程的线程局部变量的初始值,该方法是一个延迟调用方法,只有线程第一次调用set()或get()方法时,该方法才会被调用,且仅执行一次;
ThreadLocal如何做到为每个线程都维护一份独立的变量副本呢?
ThreadLocal类有一个map属性,map里面key存放当前线程对象,value存放线程局部变量副本,用线程对象做key来做区分,这样就能为每一个线程都提供一份独立的线程局部变量副本了
下面是一个简单的ThreadLocal类的实现:
/** * TheadLocal类的简单实现 */ class SimpleThreadLocal { private Map<Thread, Object> map = Collections .synchronizedMap(new HashMap<Thread, Object>()); // 设置当前线程的线程局部变量 public void set(Object value) { map.put(Thread.currentThread(),value); } // 获取当前线程的线程局部变量 public Object get() { Object value_=map.get(Thread.currentThread()); //未维护当前线程存储线程局部变量 if(value_==null&&!map.containsKey(Thread.currentThread())){ value_=initialValue(); //完成维护 map.put(Thread.currentThread(), value_); } return value_; } // 删除当前线程的本地局部变量 public void remove() { map.remove(Thread.currentThread()); } // 获取当前线程的线程局部变量的初始值 默认赋空值 protected Object initialValue() { return null; } }
ThreadLocal实例:
共享资源类:
/** * 共享对象类 * * @author zhangjian_java * */ public class SequenceNum { //把共享资源通过ThreadLocal的initialVlue方法封装进ThreadLocal中 使ThreadLocal为每一个线程都提供一份独立的变量副本,从而解决了多线程环境下相同数据访问冲突问题; private ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() { public Integer initialValue() { // 设置线程局部变量的初始值 return 9; } }; public Integer getNextNum() { // 改变线程的局部变量的值 ---此处在模拟改变当前线程的全局共享资源副本 threadLocal.set(threadLocal.get() + 1); // 获取更新后的变量副本 return threadLocal.get(); } }
线程类:
/** * 线程类 * * @author zhangjian_java * */ public class MyThread extends Thread { // 有一个共享资源对象作为属性 private SequenceNum sequenceNum; // 含参构造器 public MyThread(SequenceNum sequenceNum) { this.sequenceNum = sequenceNum; } // 重写父类的run方法 // 在当前线程中操作共享资源,模拟多线程对共享资源的并发访问 public void run() { for (int i = 0; i <= 3; i++) { System.out.println("线程:" + Thread.currentThread().getName() + "当前线程的变量副本:" + sequenceNum.getNextNum()); } } }
测试类:
@Test public void testThreadLocal() { // 创建一个共享资源类 SequenceNum sequenceNum = new SequenceNum(); // 创建多个线程 多个线程之间共享同一资源 MyThread myThread1 = new MyThread(sequenceNum); // 创建多个线程 MyThread myThread2 = new MyThread(sequenceNum); // 创建多个线程 MyThread myThread3 = new MyThread(sequenceNum); // 启动多线程 myThread1.start(); myThread2.start(); myThread3.start(); }
结果:
线程:Thread-0当前线程的变量副本:10 线程:Thread-1当前线程的变量副本:10 线程:Thread-1当前线程的变量副本:11 线程:Thread-1当前线程的变量副本:12 线程:Thread-1当前线程的变量副本:13 线程:Thread-0当前线程的变量副本:11 线程:Thread-0当前线程的变量副本:12 线程:Thread-0当前线程的变量副本:13 线程:Thread-2当前线程的变量副本:10 线程:Thread-2当前线程的变量副本:11 线程:Thread-2当前线程的变量副本:12 线程:Thread-2当前线程的变量副本:13
三个线程虽然并发的访问同一资源sequenceNum,但各个线程均有条不紊产生独立的序列号,没有对其他造成影响,
说明ThreadLoca为每一个当前线程提供一个独立的共享资源副本;
ThreadLocal和Thread同步机制的比较:
两者都是为了解决多线程下相同变量的访问冲突问题,
ThreadLocal:
提供共享资源副本,保证不破坏原数据,同一时间上允许有多个线程访问;
把共享资源通过ThreadLocal的initialVlue方法封装进ThreadLocal中 使ThreadLocal为每一个线程都提供一份独立的变量副本,从而解决了多线程环境下相同数据访问冲突问题;
Thread的同步机制:
从访问时间点控制访问数量为1;
使用对象的锁机制,使同一时间内只有一个线程访问共享资源;
ThreadLocal以空间换时间,访问并行化,对象独享化,为每一个线程都提供一份独立的变量副本,多个线程可以同时访问而互不影响;
Thread同步机制以时间换空间,访问串行化,对象共享化,仅提供一份变量,不同的线程排队访问;
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- ThreadLocal
- threadlocal
- ThreadLocal
- ThreadLocal
- 关于U8,U9中采购订单直接转PDF文件,然后直接发送给相应供应商的解决方案
- 基于Cocos2d-x学习OpenGL ES 2.0系列——OpenGL ES渲染之Shader准备(7)
- SpringMVC中使用Interceptor处理器拦截器
- mysql格式化日期
- Sqoop ERROR tool.ImportTool: Imported Failed: There is no column found in the target table
- ThreadLocal
- Codeforces 266B
- android 事件分发
- c++中的explicit关键字及隐式类型转换
- 初学四旋翼之光流定点
- Rabbitmq priority 优先级
- Tsung:开源多协议分布式负载&压力测试工具
- 静态变量/非静态变量的区别
- ECMAScript 6新特性简记