一、ThreadLocal类说明

  ThreadLocal,很容易让人望文生义,直译"本地线程"。ThreadLocal不是一个thread,是thread的局部变量。使用ThreadLocal维护变量时,它为每个使用它的线程提供独立的线程副本,每个线程可以改变自己的副本,而不会影响到其它线程对应的副本。

  从线程的角度看,目标变量就象是线程的本地变量,这也是类名中"Local"所要表达的意思。

二、ThreadLocal常用方法

①、当前变量的初始值
  protected T initialValue()

源码 如下,该方法是一个protected方法,显然是为了让子类覆盖而设计的。该方法是在get|set会调用,且只会被调一次。ThreadLocal缺省实现直接返回null

protected T initialValue() {
return null;
}

②、设置当前线程的线程局部变量值

  void set(T value)

③、返回当前线程的线程局部变量值

  public T get()

④、删除当前线程的线程局部变量值,节省内存的占用。

  public void remove()

三、下面我们通过一个具体例子,看看ThreadLocal的具体用法---Id生成器

id生成器

public interface Sequence {

    public int getId();
} public class LocalSequenceImpl implements Sequence { private ThreadLocal<Integer> container = new ThreadLocal<Integer>() { @Override
protected Integer initialValue() {
return 0;
};
}; @Override
public int getId() {
container.set(container.get() + 1);
return container.get();
} }

线程

public class ThreadLocalDemo extends Thread {

    private static Sequence obj;

    @SuppressWarnings("static-access")
public ThreadLocalDemo(Sequence obj) {
this.obj = obj;
} public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + " : " + obj.getId());
}
} public static void main(String[] args) { Sequence obj = new LocalSequenceImpl(); test(obj); } static void test(Sequence obj) { ThreadLocalDemo thread1 = new ThreadLocalDemo(obj); ThreadLocalDemo thread2 = new ThreadLocalDemo(obj); ThreadLocalDemo thread3 = new ThreadLocalDemo(obj); thread1.start();
thread2.start();
thread3.start();
}
}

结果  :

Thread-0 : 1
Thread-1 : 1
Thread-1 : 2
Thread-2 : 1
Thread-2 : 2
Thread-2 : 3
Thread-1 : 3
Thread-0 : 2
Thread-0 : 3

从上述结果,每个线程只会更改自己的局部变量,并没有发生互相干扰的情况。可以看出来,ThreadLocal为使用它的线程提供独立的副本。

不信?我们下面再通过一个不使用ThreadLocal来验证下。

public class SequenceImpl implements Sequence {

    private static int id = 0;

    @Override
public int getId() {
id = id + 1;
return id;
}
}

结果

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

仔细观察下结果,三个线程同时访问一个局部变量id,发生了互相干扰的情况。

四、拓展

看下ThreadLocal源码,底层是用Map实现的。我们可以自己设计一个ThreadLocal

public class MyThreadLocal<T> {

    private Map<Thread, T> container = Collections.synchronizedMap(new HashMap<>());

    public void set(T value) {
container.put(Thread.currentThread(), value);
} public T get() {
Thread currentThread = Thread.currentThread();
T value = container.get(Thread.currentThread());
if(value == null && !container.containsKey(currentThread)) {
value = initialValue();
container.put(Thread.currentThread(), value);
}
return value;
} protected T initialValue() {
return null;
}
}

浅析 ThreadLocal的更多相关文章

  1. 浅析ThreadLocal

    这是我的第一篇博客,条理不是很清晰,不过还是希望能对大家有所帮助. 首先明确一下这个类的作用,ThreadLocal类是用来为每个线程提供了一份变量的副本,即每个线程的局部变量.每个线程都在自己的栈空 ...

  2. ThreadLocal 从源码角度简单分析

    目录 ThreadLcoal源码浅析 ThreadLocal的垃圾回收 Java引用 ThreadLocal的回收 各线程中threadLocalMap的回收 内存泄露问题 总结 参考 ThreadL ...

  3. Java并发包2--ThreadLocal的使用及原理浅析

    ThreadLocal 是本地线程变量,是一个以ThreadLocal对象为key,任意对象为value的存储结构. 一.使用案例 1.定义线程类MyThread,代码如下: public class ...

  4. ThreadLocal浅析

    1.ThreadLocal的大体理解 ThreadLocal 又名 线程局部变量,是 Java 中一种较为特殊的 线程绑定机制,可以为每一个使用该变量的线程都提供一个变量值的副本,并且每一个线程都可以 ...

  5. 浅析Linux操作系统工作的基础

    环境:lubuntu 13.04   kernel 3.9.7 作者:SA12226265 katao 简介: 本文根据 Linux™ 系统工作基础的分析,对存储程序计算机.堆栈(函数调用堆栈)机制和 ...

  6. spring源码浅析——IOC

    =========================================== 原文链接: spring源码浅析--IOC   转载请注明出处! ======================= ...

  7. ThreadLocal原理分析与代码验证

    ThreadLocal提供了线程安全的数据存储和访问方式,利用不带key的get和set方法,居然能做到线程之间隔离,非常神奇. 比如 ThreadLocal<String> thread ...

  8. 浅析MyBatis(三):聊一聊MyBatis的实用插件与自定义插件

    在前面的文章中,笔者详细介绍了 MyBatis 框架的底层框架与运行流程,并且在理解运行流程的基础上手写了一个自己的 MyBatis 框架.看完前两篇文章后,相信读者对 MyBatis 的偏底层原理和 ...

  9. 老生常谈系列之Aop--Spring Aop原理浅析

    老生常谈系列之Aop--Spring Aop原理浅析 概述 上一篇介绍了AspectJ的编译时织入(Complier Time Weaver),其实AspectJ也支持Load Time Weaver ...

随机推荐

  1. fedora SSH

    设置无密码登陆时注意:chmod 0700 .ssh chmod 600 ~/.ssh/authorized_keys  cat /root/.ssh/id_rsa.pub  >> /ro ...

  2. Git教程(9)集中式工作方式常用的设计分支的方案

    Git是一个复杂的版本管理系统,管理代码有很多工作方式,如集中式,管理者式,司令/副官式 本文是假设选用集中式工作方式时,设计分支的方案. 中小型项目: 维护两个长期分支,分别是master 和 de ...

  3. GB2312 简体中文编码表

    GB 2312中对所收汉字进行了“分区”处理,每区含有94个汉字/符号.这种表示方式也称为区位码. 01-09区为特殊符号. 16-55区为一级汉字,按拼音排序. 56-87区为二级汉字,按部首/笔画 ...

  4. Android 权限查寻表

    示例 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android=" ...

  5. 关于pragma pack的用法(一)

    一个很重要的参数#pragma pack(n) 数据边界对齐方式:以如下结构为例: struct {                    char a;                    WOR ...

  6. 函数buf_ptr_get_fsp_addr

    #define FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID  34 /****************************************************** ...

  7. 4月数据库流行度排行榜 MySQL能否追上Oracle

    4月的数据库流行度排行榜可谓看点十足.闲言少叙,先上图: 前十名中,名次上升的都是NoSQL数据库,NoSQL凭借其对大数据处理的优势,发展越来越快.NoSQL是对众多非传统关系型数据库的总称,按存储 ...

  8. ZEat

    借助微博平台,记录每日饮食情况的Andorid程序. 项目地址:https://github.com/atskyline/ZEat 1.0.0APK下载地址:https://github.com/at ...

  9. 【转】忙里偷闲写的小例子---读取android根目录下的文件或文件夹

    原文网址:http://www.cnblogs.com/wenjiang/p/3140055.html 最近几天真的是各种意义上的忙,忙着考试,还要忙着课程设计,手上又有外包的项目,另一边学校的项目还 ...

  10. guake默认快捷键

    toggle guake visibility   切换guake可见 :F12 toggle fullscreen   切换全屏幕 :F11 quit   退出 :Shift+Ctrl+Q new ...