文档章节

并发编程实战 1.8. 线程中变量的使用 - ThreadLocal

火犀牛
 火犀牛
发布于 2016/05/11 15:53
字数 911
阅读 4
收藏 0

多线程使用同一个Runnable接口实现类的对象,那么所有的线程将共享相同的属性。也就是说,如果在A线程中修改了一个属性,那么所有的线程都会被改变。
如果,对象属性不希望被所有线程共享,可以使用ThreadLocal

范例: 1. 创建线程,每隔一段时间就修改一次里面的成员变量info,并输出。看看线程之间是否有影响。

不安全的:

package com.rr.concurrent.chapter1.recipe7.test;

import java.util.Date;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * Created by isaac_gu on 2016/5/11.
 */
public class UnsafeTask implements Runnable {

    private String info;

    @Override
    public void run() {
        for (int i = 0, len = 10; i < len; i++) {
            if (null != info) {
                System.out.printf("%s 线程中的info:%s", Thread.currentThread().getName(), info);
            }
            info = String.format("info 被 %s 线程修改!\n", Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(new Random().nextInt(10));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

测试:

package com.rr.concurrent.chapter1.recipe7.test;

import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * Created by isaac_gu on 2016/5/11.
 * 范例: 1. 创建线程,每隔一段时间就修改一次里面的成员变量info,并输出。看看线程之间是否有影响。
 */
public class UnsafeTest {
    public static void main(String[] args) {

        UnsafeTask unsafeTask = new UnsafeTask();
        //创建三个线程
        for (int i = 0, len = 3; i < len; i++) {
            new Thread(unsafeTask).start();
            try {
                TimeUnit.SECONDS.sleep(new Random().nextInt(3));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

运行结果:

Thread-2 线程中的info:info 被 Thread-2 线程修改!
Thread-0 线程中的info:info 被 Thread-2 线程修改!
Thread-0 线程中的info:info 被 Thread-0 线程修改!
Thread-1 线程中的info:info 被 Thread-0 线程修改!
Thread-2 线程中的info:info 被 Thread-1 线程修改!
Thread-2 线程中的info:info 被 Thread-2 线程修改!
Thread-0 线程中的info:info 被 Thread-2 线程修改!
Thread-2 线程中的info:info 被 Thread-0 线程修改!
Thread-1 线程中的info:info 被 Thread-2 线程修改!

可以看到,info的值被改变后,对所有的线程都是有影响的!

安全的:

package com.rr.concurrent.chapter1.recipe7.test;

import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * Created by isaac_gu on 2016/5/11.
 */
public class SafeTask implements Runnable {

    //ThreadLocal<String> info = new ThreadLocal<>();
    //需要初始化,就使用这种方式
    ThreadLocal<String> info = new ThreadLocal<String>() {
        protected String initialValue() {
            return "未赋值";
        }
    };

    @Override
    public void run() {
        for (int i = 0, len = 10; i < len; i++) {
            String info = this.info.get();
            if (null != info) {
                System.out.printf("%s 线程中的info:%s", Thread.currentThread().getName(), info);
            }
            info = String.format("info 被 %s 线程修改!\n", Thread.currentThread().getName());
            this.info.set(info);
            try {
                TimeUnit.SECONDS.sleep(new Random().nextInt(10));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

结果:

Thread-0 线程中的info:未赋值
Thread-1 线程中的info:未赋值
Thread-2 线程中的info:未赋值
Thread-0 线程中的info:info 被 Thread-0 线程修改!
Thread-0 线程中的info:info 被 Thread-0 线程修改!
Thread-0 线程中的info:info 被 Thread-0 线程修改!
Thread-1 线程中的info:info 被 Thread-1 线程修改!
Thread-2 线程中的info:info 被 Thread-2 线程修改!
Thread-1 线程中的info:info 被 Thread-1 线程修改!
Thread-0 线程中的info:info 被 Thread-0 线程修改!
Thread-2 线程中的info:info 被 Thread-2 线程修改!
Thread-2 线程中的info:info 被 Thread-2 线程修改!
Thread-2 线程中的info:info 被 Thread-2 线程修改!

 线程的变量分别为每个线程存储了各个的属性值,并提供给每个线程使用

可以使用get()和set()方法读取修改值。

还有一个 InheritableThreadLocal 类,用于继承中的属性共享。

© 著作权归作者所有

共有 人打赏支持
火犀牛
粉丝 0
博文 27
码字总数 12180
作品 0
海淀
程序员
私信 提问
Java 使用 happen-before 规则实现共享变量的同步操作

前言 熟悉 Java 并发编程的都知道,JMM(Java 内存模型) 中的 happen-before(简称 hb)规则,该规则定义了 Java 多线程操作的有序性和可见性,防止了编译器重排序对程序结果的影响。按照官方的...

stateIs0
2018/01/20
0
0
基于JVM原理、JMM模型和CPU缓存模型深入理解Java并发编程

许多以Java多线程开发为主题的技术书籍,都会把对Java虚拟机和Java内存模型的讲解,作为讲授Java并发编程开发的主要内容,有的还深入到计算机系统的内存、CPU、缓存等予以说明。实际上,在实...

leoliu168
2018/11/08
0
0
【死磕Java并发】-----J.U.C之AQS:CLH同步队列

此篇博客所有源码均来自JDK 1.8 在上篇博客【死磕Java并发】-----J.U.C之AQS:AQS简介中提到了AQS内部维护着一个FIFO队列,该队列就是CLH同步队列。 CLH同步队列是一个FIFO双向队列,AQS依赖...

chenssy
2017/06/09
0
0
Java并发编程原理与实战二十五:ThreadLocal线程局部变量的使用和原理

1.什么是ThreadLocal ThreadLocal顾名思义是线程局部变量。这种变量和普通的变量不同,这种变量在每个线程中通过get和set方法访问, 每个线程有自己独立的变量副本。线程局部变量不存在多个线...

pony1223
2018/08/14
0
0
关于JVM中long和double的读取原子性

今天看《Java并发编程实战》的书中,关于long和double的原子性有这么一段话,意思就是在JVM中,对于32位(或者以下)的数值变量都是原子性读写,但是对于long和double这种64位的操作是非原子...

Lubby
2015/11/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

centos7重置密码、单用户模式、救援模式、ls命令、chmod命令

在工作当中如果我们错误的配置了文件使服务器不能正常启动或者忘记密码不能登录系统,如何解决这些问题呢?重装系统是可以实现的,但是往往不能轻易重装系统的,下面用忘记密码作为例子讲解如...

李超小牛子
今天
3
0
Python如何开发桌面应用程序?Python基础教程,第十三讲,图形界面

当使用桌面应用程序的时候,有没有那么一瞬间,想学习一下桌面应用程序开发?行业内专业的桌面应用程序开发一般是C++,C#来做,Java开发的也有,但是比较少。本节课会介绍Python的GUI(图形用...

程序员补给栈
今天
5
0
kafka在的使用

一、基本概念 介绍 Kafka是一个分布式的、可分区的、可复制的消息系统。它提供了普通消息系统的功能,但具有自己独特的设计。 这个独特的设计是什么样的呢? 首先让我们看几个基本的消息系统...

狼王黄师傅
今天
3
0
Android JNI总结

0x01 JNI介绍 JNI是Java Native Interface的缩写,JNI不是Android专有的东西,它是从Java继承而来,但是在Android中,JNI的作用和重要性大大增强。 JNI在Android中起着连接Java和C/C++层的作...

天王盖地虎626
昨天
3
0
大数据教程(11.8)Hive1.2.2简介&初体验

上一篇文章分析了Hive1.2.2的安装,本节博主将分享Hive的体验&Hive服务端和客户端的使用方法。 一、Hive与hadoop直接的关系 Hive利用HDFS存储数据,利用MapReduce查询数据。 二、Hive与传统数...

em_aaron
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部