参考文章:ThreadLocal 与static变量

ThreadLocal是为解决多线程程序的并发问题而提出的,可以称之为线程局部变量。与一般的变量的区别在于,生命周期是在线程范围内的。
static变量是的生命周期与类的使用周期相同,即只要类存在,那么static变量也就存在。
那么一个 static 的 ThreadLocal会是什么样的呢?

看下面一个例子,

public class SequenceNumber {  private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){  public Integer initialValue(){  return 0;  }  };  public int getNextNum() {  seqNum.set(seqNum.get() + 1);  return seqNum.get();  }  public static void main(String[] args) {  SequenceNumber sn = new SequenceNumber();  TestClient t1  = new TestClient(sn);  TestClient t2  = new TestClient(sn);  TestClient t3  = new TestClient(sn);  t1.start();  t2.start();  t3.start();  t1.print();  t2.print();  t3.print();   }  private static class TestClient extends Thread {  private SequenceNumber sn;  public TestClient(SequenceNumber sn ) {  this.sn = sn;  }  public void run() {  for(int i=0; i< 3; i++) {  System.out.println( Thread.currentThread().getName()  + " --> " + sn.getNextNum());  }  }  public void print() {  for(int i=0; i< 3; i++) {  System.out.println( Thread.currentThread().getName()  + " --> " + sn.getNextNum());  }  }  }
}  

下面是结果

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

可以发现,static的ThreadLocal变量是一个与线程相关的静态变量,即一个线程内,static变量是被各个实例共同引用的,但是不同线程内,static变量是隔开的。

下面的实例能够体现Spring对有状态Bean的改造思路:
代码清单3 TopicDao:

// 非线程安全
public class TopicDao {// 一个非线程安全的变量private Connection conn;public void addTopic() {// 引用非线程安全变量Statement stat = conn.createStatement();  …}
}

由于1处的conn是成员变量,因为addTopic()方法是非线程安全的,必须在使用时创建一个新TopicDao实例(非singleton)。

下面使用ThreadLocal对conn这个非线程安全的“状态”进行改造:
代码清单4 TopicDao:

// 线程安全
package threadLocalDemo;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;public class SqlConnection {// 1. 使用ThreadLocal保存Connection变量privatestatic ThreadLocal<Connection> connThreadLocal = new ThreadLocal<Connection>();publicstatic Connection getConnection() {// 2. 如果connThreadLocal没有本线程对应的Connection创建一个新的Connection,// 并将其保存到线程本地变量中。if (connThreadLocal.get() == null) {Connection conn = getConnection();connThreadLocal.set(conn);return conn;} else {return connThreadLocal.get();// 3. 直接返回线程本地变量}}public voidaddTopic() {// 4. 从ThreadLocal中获取线程对应的Connectiontry {Statement stat = getConnection().createStatement();} catch (SQLException e) {e.printStackTrace();}}
}

为何通常将ThreadLocal变量设置为static

理由:

为了避免重复创建TSO(thread specific object,即与线程相关的变量)。
    需要注意的是:无法解决共享对象的更新问题。(引用于《阿里巴巴JAVA开发规范》)

static定义的类变量本来是可以进行变量共享的,但是因为ThreadLocal根除了对变量的共享,所以static Thread< xxx> object无法实现类的共享和同步更新。

分析

一个ThreadLocal实例对应当前线程中的一个TSO实例。因此,如果把ThreadLocal声明为某个类的实例变量(而不是静态变量),那么每创建一个该类的实例就会导致一个新的TSO实例被创建。显然,这些被创建的TSO实例是同一个类的实例。于是,同一个线程可能会访问到同一个TSO(指类)的不同实例,这即便不会导致错误,也会导致浪费(重复创建等同的对象)!因此,一般我们将ThreadLocal使用static修饰即可。

由于ThreadLocal是某个类的一个静态变量。因此,只要相应的类没有被垃圾回收掉,那么这个类就会持有对相应ThreadLocal实例的引用。

什么是ThreadLocal?

java.lang.ThreadLocal类实现了线程的本地存储,我们可以用该类来创建和管理线程。

ThreadLocal的内部实现:

ThreadLocal的内部实现包括一个类似HashMap的对象,这里称之为ThreadLocalMap。

ThreadLocalMap的key会持有对ThreadLocal实例的弱引用(Weak Reference),value会引用TSO实例。

具体的可以参考:彻底理解ThreadLocal

ThreadLocal的使用:

《thinking in java 第四版》p690

ThreadLocal 与 static 变量相关推荐

  1. 为什么jdk源码推荐ThreadLocal使用static

    ThreadLocal是线程私有变量,本身是解决多线程环境线程安全,可以说单线程实际上没必要使用. 既然多线程环境本身不使用static,那么又怎么会线程不安全.所以这个问题本身并不是问题,只是有人没 ...

  2. 【Android 异步操作】手写 Handler ( Message 消息 | ThreadLocal 线程本地变量 | Looper 中的消息队列 MessageQueue )

    文章目录 一.Message 消息 二.ThreadLocal 线程本地变量 三.Looper 中的消息队列 MessageQueue 一.Message 消息 模仿 Android 中的 Messa ...

  3. Java static变量保存在哪?

    测试环境: Microsoft Windows [版本 10.0.17134.165] java -version java version "1.8.0_171" Java(TM ...

  4. 局部变量和static变量

    局部变量:指在程序中,只在特定过程或函数中可以访问的变量,是相对于全局变量而言的.在C++.C#.Ruby这些面向对象语言中,一般只使用局部变量.在面向对象编程中现在普遍采用的是软件开发方法,因此无需 ...

  5. 一种安全的static变量Get/Set方式

    目的:避免static变量是个文件内可见的全局变量 Get: std::atomic<bool>* GetGraphVerboseStepLr() {static std::atomic& ...

  6. (转)static 变量

    一. static 变量 static变量大致分为三种用法 1. 用于局部变量中,成为静态局部变量. 静态局部变量有两个用法,记忆功能和全局生存期. 2. 用于全局变量,主要作用是限制此全局变量被其他 ...

  7. springboot下Static变量通过@Value和set方法注入失败的问题和解决办法

    首先static变量是不能直接使用@value进行注入. 但是也不是没有办法.操作如下: 1.在这个变量的类上标上注解@Component 2.通过set方法就可以,给在set方法上使用@Value注 ...

  8. java static变量销毁_JAVA里static 变量在程序执行结束后是否被消毁

    static变量是属于类的,一般情况下,程序执行结束后,类所占空间会被回收, static变量自然就被销毁了. 如下所示: public class StaticVar{ public static ...

  9. 关于static变量,请选择下面所有说法正确的内容

    若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度 若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度 设计和使用访问动态 ...

最新文章

  1. mysql 5.7 收费_MySQL5.7 常用用户操作
  2. Java平均工资再次上涨!这份宝藏资料限量免费送!
  3. 致青春VS杜蕾斯,用QQ空间电影大数据解读关联性
  4. 自学Zabbix3.0版本以上资产清单inventory
  5. mysql 分表 sphinx_sphinx(coreseek)处理分表的方案
  6. 数据结构实验之栈六:下一较大值(二)
  7. host文件注释 ubuntu_Redis and MongoDB 设置密码验证(scrapy)(win)(ubuntu)
  8. linux rmp命令安装包在哪里_一文带你了解阿里云Linux服务器的基本操作
  9. Regularized logistic regression(正则化逻辑回归)----吴恩达机器学习
  10. 携程python面试题_Python求解啤酒问题(携程2016笔试题)
  11. Python--所有的库
  12. SZTUOJ 1008.盒子游戏
  13. 【教育小程序案例】线下培训机构辅导教育
  14. JAVA-DS-排序
  15. 多线程(一) 线程概念及创建线程的方法
  16. C++学习之分式化简
  17. ESP-01S开发环境搭建及新手教程点灯教程全解详细配图(ESP8266-01s)
  18. Windows 7防火墙设置详解(一)
  19. 2020.6最新清晰的图教学!!(25行代码破解酷我音乐所有歌曲)
  20. 游戏制作RPGDreamer

热门文章

  1. 【濡白的C语言】初学者-从零开始-2(常量,一维数组,转义字符)
  2. lastIndexOf()使用方法
  3. 中e管家快速学会投资理财
  4. 副主任护师计算机考试试题,副主任护师考试科目
  5. 奉劝那些想做客户端开发学弟学妹们!呕心沥血,真情实感,字字诛心
  6. “参与感”营销策略,其实就是“宠粉”战役
  7. ETL工具(kettle) 与 ETL产品(BeeloadBeeDI) 差之毫厘,谬以千里
  8. 设置了JOB,但是 不执行
  9. Python 一元二次方程
  10. 详解setTimeout()