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. #region Json转DataTable

    #region  Json转DataTable        private DataTable Json2Dtb(string json)        {            JavaScrip ...

  2. js计算两个日期的差值

    // 获取两个比较值的毫秒数var postman_confirmtime_ms = Date.parse(new Date(data.postman_confirmtime.replace(/-/g ...

  3. 利用opencv训练样本分类

    参考:http://www.cnblogs.com/easymind223/archive/2012/07/03/2574826.html http://www.tuicool.com/article ...

  4. Linux启动过程详述

    http://www.ibm.com/developerworks/cn/linux/kernel/startup/index.html Linux启动第1步:引导内核 Linux启动第2步:内核部分 ...

  5. HDU1760 A New Tetris Game NP态

    A New Tetris Game Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  6. U盘插入电脑后,提示需要格式化U盘如何解决?

    未弹出U盘就拔掉U盘,有可能会破坏U盘的分区表.当再次把U盘插入电脑时,会提示需要格式化U盘,这是什么情况,如何解决呢?其实只要用DiskGenius硬盘恢复软件就可以解决这个问题.下面和小编一起来看 ...

  7. 广播Broadcast Receiver

    广播的类型: 1.标准广播(Normal broadcat) 完全异步执行的广播,所有广播接收器同一时间接收广播消息. 效率高,但无法被截断. 2.有序广播 同步执行的广播,同一时刻只能有一个广播接收 ...

  8. HDFS shell

    bin/hdfs -help bin/hdfs dfs -mkdir -p /yfq/test/ bin/hdfs dfs -put /etc/profile /yfq/test/profile 上传 ...

  9. Swift_1基础

    // swift中导入类库使用import,不再使用<>和""import Foundation // 输出print("Hello, World!" ...

  10. Python if 和 for 的多种写法

    a, b, c = 1, 2, 3 [对比Cpp里:c = a >b? a:b]这个写法,Python只能常规的空行,缩进吗? 人生苦短,我用python,下面介绍几种if的方便的方法. 1.常 ...