Java并发编程实践 目录

并发编程 01—— ThreadLocal

并发编程 02—— ConcurrentHashMap

并发编程 03—— 阻塞队列和生产者-消费者模式

并发编程 04—— 闭锁CountDownLatch 与 栅栏CyclicBarrier

并发编程 05—— Callable和Future

并发编程 06—— CompletionService : Executor 和 BlockingQueue

并发编程 07—— 任务取消

并发编程 08—— 任务取消 之 中断

并发编程 09—— 任务取消 之 停止基于线程的服务

并发编程 10—— 任务取消 之 关闭 ExecutorService

并发编程 11—— 任务取消 之 “毒丸”对象

并发编程 12—— 任务取消与关闭 之 shutdownNow 的局限性

并发编程 13—— 线程池的使用 之 配置ThreadPoolExecutor 和 饱和策略

并发编程 14—— 线程池 之 整体架构

并发编程 15—— 线程池 之 原理一

并发编程 16—— 线程池 之 原理二

并发编程 17—— Lock

并发编程 18—— 使用内置条件队列实现简单的有界缓存

并发编程 19—— 显式的Conditon 对象

并发编程 20—— AbstractQueuedSynchronizer 深入分析

并发编程 21—— 原子变量和非阻塞同步机制

概述

第1 部分 ThreadLocal是什么

第2 部分 ThreadLocal的接口方法

第3 部分 一个TheadLocal实例

参考

第1 部分 ThreadLocal是什么  

  ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是threadlocalvariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。ThreadLocal功能非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。

  从线程的角度看,每个线程都保持一个对其线程局部变量副本的隐式引用,只要线程是活动的并且ThreadLocal实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。

  通过ThreadLocal存取的数据,总是与当前线程相关,也就是说,JVM 为每个运行的线程,绑定了私有的本地实例存取空间,从而为多线程环境常出现的并发访问问题提供了一种隔离机制。

第2 部分 ThreadLocal的接口方法 

ThreadLocal类接口很简单,只有4个方法,我们先来了解一下。

void set(Object value)

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

public Object get()

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

public void remove()

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

protected Object initialValue()

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

set 方法:

 /**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
// 获取当前线程对象
Thread t = Thread.currentThread();
// 获取当前线程本地变量Map
ThreadLocalMap map = getMap(t);
// map不为空
if (map != null)
// 存值
map.set(this, value);
else
// 创建一个当前线程本地变量Map
createMap(t, value);
} /**
* Get the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @return the map
*/
ThreadLocalMap getMap(Thread t) {
// 获取当前线程的本地变量Map
return t.threadLocals;
}

  这里注意,ThreadLocal中是有一个Map,但这个Map不是我们平时使用的Map,而是ThreadLocalMap,ThreadLocalMap是ThreadLocal的一个内部类,不对外使用的。当使用ThreadLocal存值时,首先是获取到当前线程对象,然后获取到当前线程本地变量Map,最后将当前使用的ThreadLocal和传入的值放到Map中,也就是说ThreadLocalMap中存的值是[ThreadLocal对象, 存放的值],这样做的好处是,每个线程都对应一个本地变量的Map,所以一个线程可以存在多个线程本地变量

get方法:

 /**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
// 如果值为空,则返回初始值
return setInitialValue();
}

  有了之前set方法的分析,get方法也同理,需要说明的是,如果没有进行过set操作,那从ThreadLocalMap中拿到的值就是null,这时get方法会返回初始值,也就是调用initialValue()方法,ThreadLocal中这个方法默认返回null。当我们有需要第一次get时就能得到一个值时,可以继承ThreadLocal,并且覆盖initialValue()方法。

第3 部分 一个TheadLocal实例

 /**
*
* @ClassName: SequenceNumber
* @author xingle
* @date 2015-3-9 上午9:54:23
*/
public class SequenceNumber {
//①通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值
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();
//③ 3个线程共享sn,各自产生序列号
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(){
//④每个线程打出3个序列值
for (int i = 0 ;i<3;i++){
System.out.println("thread["+Thread.currentThread().getName()+"] sn["+sn.getNextNum()+"]");
}
}
} }

  通常我们通过匿名内部类的方式定义ThreadLocal的子类,提供初始的变量值,如①处所示。TestClient线程产生一组序列号,在③处,我们生成3个TestClient,它们共享同一个SequenceNumber实例。运行以上代码,在控制台上输出以下的结果:

  每个线程所产生的序号虽然都共享同一个Sequence Number实例,但它们并没有发生相互干扰的情况,而是各自产生独立的序列号,这是因为我们通过ThreadLocal为每一个线程提供了单独的副本。


参考:

1.ThreadLocal

2.Java线程(篇外篇):线程本地变量ThreadLocal

3.线程本地变更,即ThreadLocal-->Spring事务管理

并发编程 01—— ThreadLocal的更多相关文章

  1. Python并发编程01 /操作系统发展史、多进程理论

    Python并发编程01 /操作系统发展史.多进程理论 目录 Python并发编程01 /操作系统发展史.多进程理论 1. 操作系统 2. 进程理论 1. 操作系统 定义:管理控制协调计算机中硬件与软 ...

  2. Java并发编程:ThreadLocal

    Java并发编程:深入剖析ThreadLocal   Java并发编程:深入剖析ThreadLocal 想必很多朋友对ThreadLocal并不陌生,今天我们就来一起探讨下ThreadLocal的使用 ...

  3. 【并发编程】ThreadLocal其实很简单

    什么是ThreadLocal ThreadLocal有点类似于Map类型的数据变量.ThreadLocal类型的变量每个线程都有自己的一个副本,某个线程对这个变量的修改不会影响其他线程副本的值.需要注 ...

  4. 【并发编程】ThreadLocal的兄弟InheritableThreadLocal

    本博客系列是学习并发编程过程中的记录总结.由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅. 并发编程系列博客传送门 引子 public class InheritableT ...

  5. 并发编程之五--ThreadLocal

    ThreadLocal是什么 早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路.使用这个工具类可以很简洁地 ...

  6. Java并发编程(01):线程的创建方式,状态周期管理

    本文源码:GitHub·点这里 || GitEE·点这里 一.并发编程简介 1.基础概念 程序 与计算机系统操作有关的计算机程序.规程.规则,以及可能有的文件.文档及数据. 进程 进程是计算机中的程序 ...

  7. Java并发编程--理解ThreadLocal

    另一篇博文:Hibernet中的ThreadLocal使用 http://www.cnblogs.com/gnivor/p/4440776.html 本文参考:http://blog.csdn.net ...

  8. java并发编程学习: ThreadLocal使用及原理

    多线程应用中,如果希望一个变量隔离在某个线程内,即:该变量只能由某个线程本身可见,其它线程无法访问,那么ThreadLocal可以很方便的帮你做到这一点. 先来看一下示例: package yjmyz ...

  9. Java并发编程:ThreadLocal的使用以及实现原理解析

    前言 前面的文章里,我们学习了有关锁的使用,锁的机制是保证同一时刻只能有一个线程访问临界区的资源,也就是通过控制资源的手段来保证线程安全,这固然是一种有效的手段,但程序的运行效率也因此大大降低.那么, ...

随机推荐

  1. java ide 导出可运行jar包

    常常会用到写个jar搬到其他地方运行的情况,这里做个笔记记录下如何利用eclipse或者idea导出jar. 导出jar包最好的方式个人认为是把依赖的包都打包进目标jar,这样一个jar可以很happ ...

  2. 数据库中的左连接(left join)和右连接(right join)区别

    Left Join / Right Join /inner join相关 关于左连接和右连接总结性的一句话: 左连接where只影向右表,右连接where只影响左表. Left Join select ...

  3. 两个NetSuite之间历史交易数据迁移的具体方案

    背景与展望: 比如:公司要上市往往会要求提供过去几年的营业数据和报表等信息, 而这些信息来源于正在一直运营使用的ERP和财务系统是最可靠与真实的. NetSuite实现的ERP和财务系统的完美结合,随 ...

  4. C扩展python的module和Type

    有许多理由给CPython写扩展,比如 1.性能低 2.重复用别人的C/C++代码 3.在自己的程序中定制python 4.为了方便 等等. 写这种扩展其实都是套路,不过最好要有对CPython源码有 ...

  5. [转]C#常用开源类库收集

    .net PDF 类库 PDFsharp PDFsharp是一款可以让.NET框架支持的任何语言很容易的创建PDF文件的类库. ASP.NET FO PDF FO PDF 是一款C#编写类似于ASP. ...

  6. mybatis.xml文件中#与$符号的区别以及数学符号的处理

    1.#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以有效防止sql注入. #{}可以接收简单类型值或po ...

  7. OpenLayers添加点【php请求MySQL数据库返回GeoJSON数据】

    php请求MySQL数据库返回GeoJSON数据的实现方法请参见: http://www.cnblogs.com/marost/p/6234514.html OpenLayers[v3.19.1-di ...

  8. Oracle(创建序列)

    概念: 所谓序列,在oracle中就是一个对象,这个对象用来提供一个有序的数据列,这个有序的数据列的值都不重复. 1.序列可以自动生成唯一值 2.是一个可以被共享的对象 3.典型的用来生成主键值的一个 ...

  9. Building Websites in ASP.NET

    ASP.NET offers three frameworks for creating web applications: Web Forms, ASP.NET MVC, and ASP.NET W ...

  10. 结合nodejs开发aspnet5项目

    1.安装kvm   官方教程地址:https://github.com/ligershark/Kulture 打开 powershell命令窗口,找不到可以在开始菜单菜单那块输入 powershell ...