文档章节

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

阿拉德大陆的魔法师
 阿拉德大陆的魔法师
发布于 2016/11/23 16:30
字数 670
阅读 50
收藏 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

 

© 著作权归作者所有

共有 人打赏支持
阿拉德大陆的魔法师
粉丝 23
博文 91
码字总数 83019
作品 0
西城
程序员
安卓开发必备知识体系:Java篇

大家好我是张拭心,自从各位朋友帮点广X开始,我发现我每天更有奔头了,走起路来也更有劲了,说啥也得更新的勤快一点。不过放心,我一定推送有价值的内容给大家,还请朋友们照旧动动手指点点...

d29h1jqy3akvx
05/10
0
0
干货系列1:Java互联网网站开发工程师 的技术提高与晋升路线(技术专精)

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

半饱即好
06/26
0
0
Java面试:投行的15个多线程和并发面试题

本文由ImportNew -一杯哈希不加盐 翻译自dzone。欢迎加入翻译小组。转载请见文末要求。 多线程和并发问题已成为各种 Java 面试中必不可少的一部分。如果你准备参加投行的 Java 开发岗位面试,...

ImportNew
08/23
0
0
读书笔记之《Java并发编程的艺术》-并发编程容器和框架(重要)

读书笔记部分内容来源书出版书,版权归本书作者,如有错误,请指正。 欢迎star、fork,读书笔记系列会同步更新 git https://github.com/xuminwlt/j360-jdk module j360-jdk-thread/me.j360....

Hi徐敏
2015/11/11
0
1
如果你想学习Java,那么就来看这篇文章

一、前言 我是从大二开始学习的Java,当时的目标是Java Web开发,当时并不想考研,所以当时的学习是以就业为主,现在我大三了,学习Java Web开发已经一年了,因为种种原因,决定要考研,所以...

Jivanmoon
08/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

67:shell脚本介绍 | shell脚本结构 | 执行data命令用法 | shell脚本中变量

1、shell脚本介绍: shell是一种脚本语言和传统的开发语言相比,会比较简单: shell有自己语法,可以支持逻辑判断、循环等语法: 可以自定义函数,目的是减少重复的代码: shell是系统命令的集合...

芬野de博客
28分钟前
1
0
json schema

json schema是用来验证和描述json对象结构的。 在线验证:https://www.jsonschemavalidator.net/ json schema 编辑器,推荐VSCode,写上"$schema": "https://raw.githubusercontent.com/jso......

谷永权
33分钟前
1
0
部署生产级的 Kubernetes 集群,使用kubespray

部署生产级的 Kubernetes 集群,使用kubespray 项目源码,https://github.com/openthings/kubespray 国内部署,https://github.com/zhangguanzhang/Kubernetes-ansible 欢迎加入 kubernetes......

openthings
40分钟前
0
0
73.分发系统介绍 expect脚本远程登录 执行命令 传递参数

20.27 分发系统介绍 20.28 expect脚本远程登录 20.29 expect脚本远程执行命令 20.30 expect脚本传递参数 20.27 分发系统介绍: 场景:业务越来越大。用的比如app,后端(也就是服务器)所使用...

王鑫linux
45分钟前
0
0
SpringBoot应用不能访问项目静态页面html问题处理

问题描述:SpringBoot搭建web应用在eclipse中启动能够正常访问页面,打包成jar之后不能访问到页面,没有任何出错提示。 环境:使用的是前后端分离架构,没有使用模板,前端html和静态文件放到...

奋斗小蜗牛
48分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部