2019独角兽企业重金招聘Python工程师标准>>>

ThreadLocal 让每个线程可以保留一份变量的私有"版本" 。 早在 JDK 1.2 的版本中就提供 java.lang.ThreadLocal , ThreadLocal 为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。 ThreadLocal 并不是一个 Thread ,而是 Thread 的局部变量。当使用 ThreadLocal 维护变量时, ThreadLocal 为每个使用该变量的线程提供独立的变量副本。

ThreadLocal的接口方法:

  1. void set(Object value):设置当前线程的线程局部变量的值。
  2. public Object get():该方法返回当前线程所对应的线程局部变量。
  3. public void remove():将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。

需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
      protected Object initialValue():返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。

在JDK5.0中,ThreadLocal已经支持泛型,该类的类名已经变为ThreadLocal<T>。

ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本。

下面是一个多线程向一个表插入数据的例子:

package com.lucky.concurrent;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;public class ThreadLocalDemo extends Thread {@Overridepublic void run() {ThradTask.executeUpdate();}public static void main(String[] args) {for (int i = 0; i < 900; i++) {ThreadLocalDemo demo = new ThreadLocalDemo();demo.start();}}
}class ThradTask {static String sql = "insert into job_log(id, jobtype, logdate, status, ext1, ext2, ext3, log_time) values (seq_job_log.nextval, 1, sysdate, 1, null, null, null, sysdate)";public static void executeUpdate() {Connection con = null;try {con = DbUtil.getConnection();con.setAutoCommit(false); // 关闭自动提交事务(开启事务)con.prepareStatement(sql).executeUpdate();con.commit();} catch (SQLException e) {e.printStackTrace();} finally {DbUtil.closeConnection();System.out.println("insert success ");}}}class DbUtil {private static Connection con;// 静态连接对象,全部对象共享一个public static Connection getConnection() {try {Class.forName("oracle.jdbc.driver.OracleDriver");con = DriverManager.getConnection("jdbc:oracle:thin:@xx.xx.xx.xx:1521:orcl", "dev_tc","123456");} catch (Exception e) {e.printStackTrace();}return con;}public static void closeConnection() {if (con != null) {try {con.close();} catch (SQLException e) {e.printStackTrace();}}}
}

看结果:

数据库关闭的连接,这个错误跟 Connection 有关系,那我就将主要精力放在检查 Connection 相关的代码上吧。是不是 Connection 不应该是 static 的呢?我当初设计成 static 的主要是为了让 DBUtil 的 static 方法访问起来更加方便,用 static 变量来存放 Connection 也提高了性能啊。怎么搞呢?接着就是重构了DbUtil。看下面的代码。只贴出DbUtil的代码。

class DbUtil {private static ThreadLocal<Connection> local = new ThreadLocal<Connection>();public static Connection getConnection() {try {Connection localCon = local.get();if (localCon == null) {Class.forName("oracle.jdbc.driver.OracleDriver");localCon = DriverManager.getConnection("jdbc:oracle:thin:@xx.xx.xx.xx:1521:orcl", "dev_tc","123456");local.set(localCon);}} catch (Exception e) {//获取链接报错,比如超过最大连接数则销毁当前任务。<正常情况下是不能这样做>Thread.currentThread().stop();e.printStackTrace();}return local.get();}public static void closeConnection() {Connection con = local.get();if (con != null) {try {con.close();} catch (SQLException e) {e.printStackTrace();}finally{local.remove();//将当前线程局部变量的值删除,目的是为了减少内存的占用}}}
}

运行结果:

下面是另一个例子:

package test;import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadLocalTest {private static class Task implements Runnable {private static ThreadLocal<Integer> number = new ThreadLocal<Integer>() {@Overrideprotected Integer initialValue() {return 0;}};public int getNumber() {number.set(number.get() + 1);return number.get();}@Overridepublic void run() {try {Thread.sleep(new Random().nextInt(5000));} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "   "+ getNumber());}}public void run() {ExecutorService pool = Executors.newFixedThreadPool(10);for (int i = 0; i < 10; i++) {pool.execute(new ThreadLocalTest.Task());}pool.shutdown();}public static void main(String[] args) {new ThreadLocalTest().run();}}

运行结果:每一个线程初始化值都是1。获得的结果就是static变量没有多线程共享。多线程安全。

此文章是学习了http://my.oschina.net/huangyong/blog/159489 这位大牛的而出世的。

下次继续写。先睡觉。

转载于:https://my.oschina.net/jielucky/blog/160613

ThreadLocal 简介相关推荐

  1. ThreadLocal 简介 案例 源码分析 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  2. java: ThreadLocal简介

    ThreadLocal中有map会存储每个线程的信息,这样,每个线程相当于拥有了局部变量. package com.baobaotao;class Ticket{public int count = ...

  3. 【Java】Java中ThreadLocal简介以及源码

    文章目录 1.概述 1.1 什么是ThreadLocal变量 2.API 方法 4.3 ThreadLocalMap 4.1 ThreadLocal 4.1.1 set 4.1.2 get 4.1.2 ...

  4. threadlocal内存泄露_ThreadLocal 简介

    本文转载于SegmentFault社区 作者:莫小点还有救 1. ThreadLocal简介 通常情况下,我们创建的变量是可以被任何一个线程访问并修改的.如果想实现每一个线程都有自己的专属本地变量该如 ...

  5. 面试官:听说你精通并发编程,来说说你对ThreadLocal的理解

    ThreadLocal 简介 ThreadLocal 是一个解决多线程并发问题的工具类,ThreadLocal有的人可能理解为本地线程,这个并不是正确的理解.「ThreadLocal并不是一个线程,应 ...

  6. Java中的ThreadLocal详解

    一.ThreadLocal简介 多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线 ...

  7. 线程本地ThreadLocal的介绍与使用!

    ThreadLocal简介 我们通过上两篇的学习,我们已经知道了变量值的共享可以使用public static变量的形式,所有的线程都使用同一个被public static修饰的变量. 那么如果我们想 ...

  8. Java8 ThreadLocal 源码分析

    可参考文章: Java8 IdentityhashMap 源码分析 IdentityhashMap 与 ThreadLocalMap 一样都是采用线性探测法解决哈希冲突,有兴趣的可以先了解下 Iden ...

  9. 深入理解并发容器ThreadLocal

    在涉及到多线程需要共享变量的时候,一般有两种方法:其一就是使用互斥锁,使得在每个时刻只能有一个线程访问该变量,好处就是便于编码(直接使用synchronized关键字进行同步访问),缺点在于这增加了线 ...

最新文章

  1. Java入门之HelloWorld
  2. php 访问网页返回值,Ping网站并用PHP返回结果
  3. opencv进阶学习笔记7:直方图,直方图均衡化,直方图比较,直方图反向投影
  4. javafx中的tree_JavaFX中的塔防(5)
  5. 【POJ - 1459】Power Network(网络流最大流,建图)
  6. python中向类中动态添加新特性及删除属性方法
  7. 信息学奥赛C++语言:猴子选大王
  8. 计算机教室管理员应知应会,教室管理
  9. navicat下载安装教程
  10. [微信小程序开发者工具] × #initialize
  11. coq 函数式编程--Basics.v
  12. 微信第三方平台代小程序实现业务
  13. 如何计算算法的时间复杂度
  14. 分布式计算原理之分布式协调与同步(1)——分布式互斥
  15. 20191207-CHKDSK命令修复磁盘教程
  16. 左特征向量与右特征向量
  17. 查看mysql 表 被人删除_MySQL 删除数据表
  18. Outlook2016关联QQ邮箱
  19. 2019计算机考研心得
  20. 服务器托管你应该了解的知识

热门文章

  1. 十、oracle 常用函数
  2. 纯中文C++代码,可运行
  3. [ZJOI2007]棋盘制作 报表统计 矩阵游戏 时态同步
  4. LeetCode: Search a 2D Matrix
  5. XML 学习 (3)
  6. Jsoup:用Java也可以爬虫,怎么使用Java进行爬虫,用Java爬取网页数据,使用Jsoup爬取数据,爬虫举例:京东搜索
  7. java进城杀不死怎么办_linux – 如何杀死永不死的进程?
  8. 为什么parsefloat加出来还是字符串_为什么水质检测达标家里的自来水管流出来的水却还是脏的?...
  9. C++string类知识点总结
  10. 16、计算机图形学——基于AABB进行光线追踪的加速(下)