文档章节

Java并发编程初级篇(八):ThreadLocal

阿拉德大陆的魔法师
 阿拉德大陆的魔法师
发布于 2016/11/23 16:30
字数 670
阅读 58
收藏 1

 

在Java中,如果使用了Runnable接口的实现类。用这个实现类的一个实例对象来启动多个线程,那么这个类中的变量就会被多个线程共用,不管你住没注意,这在“Java并发编程(一):线程实现与运行的两种方式”中已经出现过了。

我们现在基于这个例子来改造一下,看如何用一个Runnable的实例对象创建多个线程类,并且让每一个线程都有自己的私有属性。

我们用Java API提供的ThreadLocal类来替换int变量,ThreadLocal类作为Java API提供的一个线程局部变量,它是和线程绑定的,每一个线程都会有一个独立的副本。

通过查看ThreadLocal类的原代码,我们可以发现每一个线程内部都会有一个ThreadLocalMap属性,这个类的内部实现是一个Entry[]数组,(key=ThreadLocal,value=ThreadLocal对象的绑定值)。当你调用ThreadLocal.get()方法的时候,它就会获取当前线程对象的ThreadLocalMap属性中以ThreadLocal对象为健对应的值。如果不存在就会调用setInitialValue()方法,然后将initialValue()方法返回的值设置到ThreadLocalMapEntry[]数组中,并返回这个值。

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

/**
     * Variant of set() to establish initialValue. Used instead
     * of set() in case user has overridden the set() method.
     *
     * @return the initial value
     */
    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

下面看我们的实现代码,为线程定义一个ThreadLocal类型属性,具体实现ThreadLocal中的initialValue()方法来为这个ThreadLocal对象属性赋一个初始值。然后使用MyRunnable的一个实例启动三个线程。

public class MyRunnable implements Runnable {
    private ThreadLocal<Integer> num = new ThreadLocal<Integer>(){
        @Override
        protected Integer initialValue() {
            return 3;
        }
    };

    @Override
    public void run() {
        while (num.get() > 0) {
            System.out.println("Thread:" + Thread.currentThread().getName() + ", consume " + num.get());
            num.set(num.get() - 1);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Runnable runnable = new MyRunnable();

        Thread thread1 = new Thread(runnable);
        Thread thread2 = new Thread(runnable);
        Thread thread3 = new Thread(runnable);

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

查看控制台日志,你会发现每一个线程都使用了一个独立的num值。

Thread:Thread-0, consume 3
Thread:Thread-2, consume 3
Thread:Thread-1, consume 3
Thread:Thread-0, consume 2
Thread:Thread-1, consume 2
Thread:Thread-2, consume 2
Thread:Thread-2, consume 1
Thread:Thread-1, consume 1
Thread:Thread-0, consume 1

 

© 著作权归作者所有

共有 人打赏支持
阿拉德大陆的魔法师
粉丝 26
博文 91
码字总数 83019
作品 0
西城
程序员
私信 提问
干货系列1:Java互联网网站开发工程师 的技术提高与晋升路线(技术专精)

前几天写了自己对于Java软件开发工程师职业发展规划方面的一些感悟,陆续收到一些反馈,希望我能再就Java工程师不同的开发(职责)方向谈谈职业发展问题。(上一篇:Java软件开发工程师的自我...

半饱即好
2018/06/26
0
0
Java 10大优点—Part4—Java内存模型

在忙着参加在爱沙尼亚进行的 TEDx talk 演讲活动以及在比利时举办的一届非常忙碌的Devoxx 会议的间隙,我将继续推进 Java’s Rocking 的系列博文。 对还没有接触过这个系列博文的读者,不妨先...

foxlee
2013/12/09
339
1
Java 并发编程源码解析汇总篇

java并发编程,内存模型 java并发编程,volatile内存实现和原理 Java并发编程,并发基础 Java 并发编程,线程池(ThreadPoolExecutor)源码解析 Java并发编程,Executor 框架介绍 Java并发编...

郑加威
2018/12/23
0
0
JavaEE程序员必读图书大推荐

下面是我根据多年的阅读和实践经验,给您推荐的一些图书: 第一部分: Java语言篇 1 《Java编程规范》 星级: 适合对象:初级,中级 介绍:作者James Gosling(Java之父),所以这本书我觉得...

长平狐
2012/11/12
1K
0
那些年,关于 Java 的那些事儿

版权声明:Follow your heart and intuition. https://blog.csdn.net/qq_35246620/article/details/78695893 温馨提示:本系列博文(含示例代码)已经同步到 GitHub,地址为「java-skills」,...

维C果糖
2017/12/02
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Windows 上安装 Scala

在安装 Scala 之前需要先安装 Java 环境,具体安装的详细方法就不在这里描述了。 您可以自行搜索我们网站中的内容获得其他网站的帮助来获得如何安装 Java 环境的方法。 接下来,我们可以从 ...

honeymose
24分钟前
0
0
数据库篇多表操作

第1章 多表操作 实际开发中,一个项目通常需要很多张表才能完成。例如:一个商城项目就需要分类表(category)、商品表(products)、订单表(orders)等多张表。且这些表的数据之间存在一定的关系...

stars永恒
今天
2
0
nginx日志自动切割

1.日志配置(Nginx 日志) access.log----记录哪些用户,哪些页面以及用户浏览器,IP等访问信息;error.log------记录服务器错误的日志 #配置日志存储路径:location / {      a...

em_aaron
昨天
3
0
java 反射

基本概念 RTTI,即Run-Time Type Identification,运行时类型识别。RTTI能在运行时就能够自动识别每个编译时已知的类型。   要想理解反射的原理,首先要了解什么是类型信息。Java让我们在运...

细节探索者
昨天
2
0
推荐转载连接

https://www.cnblogs.com/ysocean/p/7409779.html#_label0

小橙子的曼曼
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部