`
lhgyy00
  • 浏览: 139644 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

java基础 ThreadLocal

 
阅读更多

今天学习了ThreadLocal,和大家分享下,理解的不是很透彻。

API中的解释是:

该类提供了线程局部 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 getset 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。

网上一些说是(1)为了解决多线程并发的问题,我没有看出来;

另有一些说法是(2)ThreadLocal和多线程并发没有什么关系。ThreadLocal模式是为了解决单线程内的跨类跨方法调用的,有点AOP的味道;

此处待慢慢学习,不做评论。

 

实现原理,这边写了一个简单的SmipleThreadLocal的例子,代码粗糙,但是和ThreadLocal的设计思路是一样的

 

 

 

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Eva

 * threadLocal 的雏形
 */
public class SimpleThreadLocal {
 private Map valueMap = Collections.synchronizedMap(new HashMap());

 public void set(Object newValue) {
  valueMap.put(Thread.currentThread(), newValue);// 键为线程对象,值为本线程的变量副本
 }

 public Object get() {
  Thread thread = Thread.currentThread();
  Object o = valueMap.get(thread);// 本线程对应的变量
  if (o == null && !valueMap.containsKey(thread)) {
   o = initialValue();// 如果map中不存在,则初始化并且放在Map中
   valueMap.put(thread, o);
  }
  return o;

 }

 public Object initialValue() {
  return null;
 }

 public void remove() {
  valueMap.remove(Thread.currentThread());
 }
}

 

 

ThreadLocal的接口方法:

  • void set(Object value)

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

  • public Object get()

该方法返回当前线程所对应的线程局部变量。

  • public void remove()

将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。

  • protected Object initialValue()

返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。

值得一提的是,在JDK5.0中,ThreadLocal已经支持泛型,该类的类名已经变为ThreadLocal<T>。API方法也相应进行了调整,新版本的API方法分别是void set(T value)、T get()以及T initialValue()。

 

ThreadLocal的使用

(1)自己写了一个多线程的:

public class SequenceNumber {
 // 通过匿名内部类ThreadLocal的initalValue方法指定初始值
 private static ThreadLocal seqNum = new ThreadLocal() {
  protected Object initialValue() {
   return new Integer(0);
  };
 };

 // 获得下一个序列值
 public int getNextNum() { 
  seqNum.set(new Integer(Integer.parseInt(seqNum.get().toString()) + 1));
  return Integer.parseInt(seqNum.get().toString());
 }

 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();
 }

 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[" + Thread.currentThread().getName()
      + "]===sn[" + sn.getNextNum()+ "]");
   }
  }
 }
}

输出结果:

//------------------------------------------------------------------

thread[Thread-1]===sn[1]
thread[Thread-1]===sn[2]
thread[Thread-1]===sn[3]
thread[Thread-2]===sn[1]
thread[Thread-2]===sn[2]
thread[Thread-2]===sn[3]
thread[Thread-0]===sn[1]
thread[Thread-0]===sn[2]
thread[Thread-0]===sn[3]
//------------------------------------------------------------------

 

 

 

 

但是本人觉得这个不足以说明他是解决多线程并发的问题。

 

 

 

 (2)下面的两个是在网上摘抄的:

  Hibernate的文档时看到了关于使ThreadLocal管理多线程访问的部分。具体代码如下

  1. public static final ThreadLocal session = new ThreadLocal();

  2. public static Session currentSession() {

  3. Session s = (Session)session.get();

  4. //open a new session,if this session has none

  5. if(s == null){

  6. s = sessionFactory.openSession();

  7. session.set(s);

  8. }

  return s;

  9. }

  我们逐行分析

  1。 初始化一个ThreadLocal对象,ThreadLocal有三个成员方法 get()、set()、initialvalue()。

  如果不初始化initialvalue,则initialvalue返回null。

  3。session的get根据当前线程返回其对应的线程内部变量,也就是我们需要的net.sf.hibernate.Session(相当于对应每个数据库连接).多线程情况下共享数据库链接是不安全的。ThreadLocal保证了每个线程都有自己的s(数据库连接)。

  5。如果是该线程初次访问,自然,s(数据库连接)会是null,接着创建一个Session,具体就是行6。

  6。创建一个数据库连接实例 s

  7。保存该数据库连接s到ThreadLocal中。

  8。如果当前线程已经访问过数据库了,则从session中get()就可以获取该线程上次获取过的连接实例。

(3) 当要给线程初始化一个特殊值时,需要自己实现ThreadLocal的子类并重写该方法,通常使用一个内部匿名类对ThreadLocal进行子类化,EasyDBO中创建jdbc连接上下文就是这样做的:

  public class JDBCContext{

  private static Logger logger = Logger.getLogger(JDBCContext.class);

  private DataSource ds;

  protected Connection connection;

  private boolean isValid = true;

  private static ThreadLocal jdbcContext;

  private JDBCContext(DataSource ds){

  this.ds = ds;

  createConnection();

  }

  public static JDBCContext getJdbcContext(javax.sql.DataSource ds)

  {

  if(jdbcContext==null)jdbcContext=new JDBCContextThreadLocal(ds);

  JDBCContext context = (JDBCContext) jdbcContext.get();

  if (context == null) {

  context = new JDBCContext(ds);

  }

  return context;

  }

  private static class JDBCContextThreadLocal extends ThreadLocal {

  public javax.sql.DataSource ds;

  public JDBCContextThreadLocal(javax.sql.DataSource ds)

  {

  this.ds=ds;

  }

  protected synchronized Object initialValue() {

  return new JDBCContext(ds);

  }

  }

  }

 

 

 

 

分享到:
评论

相关推荐

    免费分享 Java面试笔记 面试八股文 计算机网络基础

    本资源适用于运营商、Java开发校招面试基础巩固,包含计算机网络、Java基础、Java集合、Java并发编程、JVM、MySQL、Spring、MyBatis、Redis、Rocket MQ的经典面试题目,涵盖每个知识点的各个方面,能够很好的提升...

    ThreadLocal原理及在多层架构中的应用.pdf

    ThreadLocal的基本原理,核心机制,源码,ThreadLocal在分布式架构中的应用,ThreadLocal在基础架构,开源中间件,使用非常广泛,建议掌握。

    Quartz-ThreadLocal.rar

    本地学习练习demo的eclipse工作空间:主要包括多线程的相关demo以及quartz调度的简单实现和其他java基础的demo练习

    【Java入门知识图谱】帮助Java初学者成长

    Java基础 【对线面试官】Java注解 【对线面试官】Java泛型 【对线面试官】Java NIO 【对线面试官】Java反射 && 动态代理 爪哇 【对线面试官】多线程基础 【对线面试官】 CAS 【对线面试官】同步进行 【对线面试官】...

    java线程学习笔记

    2.3 线程本地存储(Java.lang.ThreadLocal) 15 2.4 线程阻塞 17 2.4.1 调用sleep(millisecond)使任务进入休眠状态 17 2.4.2 等待输出与输入 17 2.4.3 对象锁不可用 17 2.4.4 通过wait()使线程挂起。 17 2.5 线程...

    JVM的基础和调优【JMM 内存结构 GC OOM 性能调优 ThreadLocal】

    JVM的基础和调优【JMM 内存结构 GC OOM 性能调优 ThreadLocal】 内存泄露:是指程序在申请内存后,无法释放已申请的内存空间就造成了内存泄露, 一次的内存泄露似乎不会有大的影响,但是内存泄露堆积的后果就是内存...

    Java中的线程同步与ThreadLocal无锁化线程封闭实现

    主要介绍了Java中的线程同步与ThreadLocal无锁化线程封闭实现,Synchronized关键字与ThreadLocal变量的使用是Java中线程控制的基础,需要的朋友可以参考下

    java面试题及技巧4

    │ │ 一些其它网站的java基础精华贴.txt │ │ 新建 文本文档.txt │ │ 经验总结.txt │ │ 资料目录.txt │ │ 题目.txt │ │ │ ├─HTML Pages │ │ │ Desktop_.ini │ │ │ Low Level Security in Java....

    java面试题目与技巧1

    │ │ 一些其它网站的java基础精华贴.txt │ │ 新建 文本文档.txt │ │ 经验总结.txt │ │ 资料目录.txt │ │ 题目.txt │ │ │ ├─HTML Pages │ │ │ Desktop_.ini │ │ │ Low Level Security in Java....

    java面试题以及技巧

    │ │ 一些其它网站的java基础精华贴.txt │ │ 新建 文本文档.txt │ │ 经验总结.txt │ │ 资料目录.txt │ │ 题目.txt │ │ │ ├─HTML Pages │ │ │ Desktop_.ini │ │ │ Low Level Security in Java....

    Java并发编程实战

    3.3.3 ThreadLocal类 3.4 不变性 3.4.1 Final域 3.4.2 示例:使用Volatile类型来发布不可变对象 3.5 安全发布 3.5.1 不正确的发布:正确的对象被破坏 3.5.2 不可变对象与初始化安全性 3.5.3 安全发布的常用...

    架构探险:从零开始写Java Web框架

    《架构探险:从零开始写Java Web框架》首先从一个简单的 Web 应用开始,让读者学会如何使用 IDEA... 《架构探险:从零开始写Java Web框架》适合具备 Java 基础知识,熟悉 Web 相关理论,并想成为架构师的程序员阅读。

    Java常见面试题208道.docx

    面试题包括以下十九部分:Java 基础、容器、多线程、反射、对象拷贝、Java Web 模块、异常、网络、设计模式、Spring/Spring MVC、Spring Boot/Spring Cloud、Hibernate、Mybatis、RabbitMQ、Kafka、Zookeeper、MySql...

    架构探险-从零开始写javaweb框架

    《架构探险:从零开始写Java Web框架》首先从一个简单的 Web 应用开始,让读者学会如何使用 IDEA... 《架构探险:从零开始写Java Web框架》适合具备 Java 基础知识,熟悉 Web 相关理论,并想成为架构师的程序员阅读。

    疯狂JAVA讲义

    第1章 Java概述 1 1.1 Java语言的发展简史 2 1.2 Java的竞争对手及各自优势 4 1.2.1 C#简介和优势 4 1.2.2 Ruby简介和优势 4 1.2.3 Python的简介和优势 5 1.3 Java程序运行机制 5 1.3.1 高级语言的运行机制 6...

    java并发编程面试题

    java并发编程 基础知识,守护线程与线程, 并行和并发有什么区别? 什么是上下文切换? 线程和进程区别 什么是线程和进程? 创建线程有哪几种方式?,如何避免线程死锁 线程的 run()和 start()有什么区别? 什么是 ...

    实战Java高并发程序设计(第2版)PPT模板.pptx

    4锁的优化及注意事项 4.1有助于提高锁性能的几点建议 4.2java虚拟机对锁优化所做的努力 4.3人手一支笔:threadlocal 4.4无锁 4.5有关死锁的问题 4.2Java虚拟机对锁优化所做的努力 4.3人手一支笔:ThreadLocal 4.4...

    架构探险——从零开始写Java Web框架 绝对完整!强烈推荐

    然后基于传统 Servlet 框架搭建一款轻量级 Java Web 框架,一切都是从零开始,逐个实现类加载器、Bean容器、IoC框架、MVC框架,所涉及的代码也是整个框架的核心基础。为了使框架具备AOP特性,从代理技术讲到 AOP ...

    java多线程安全性基础介绍.pptx

    java多线程安全性基础介绍 线程安全 正确性 什么是线程安全性 原子性 竞态条件 i++ 读i ++ 值写回i 可见性 JMM 由于cpu和内存加载速度的差距,在两者之间增加了多级缓存导致,内存并不能直接对cpu可见。 ...

    架构探险――从零开始写Java Web框架_黄勇

    然后基于传统 Servlet 框架搭建一款轻量级 Java Web 框架,一切都是从零开始,逐个实现类加载器、Bean 容器、IoC 框架、MVC 框架,所涉及的代码也是整个框架的核心基础。为了使框架具备 AOP 特性,从代理技术讲到 ...

Global site tag (gtag.js) - Google Analytics