文档章节

并发编程实战 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
01/20
0
0
Java 编程之美:并发编程高级篇之一

本文来自作者 追梦 在 GitChat 上分享 「Java 编程之美:并发编程高级篇之一」 编辑 | 工藤 前言 借用 Java 并发编程实践中的话:编写正确的程序并不容易,而编写正常的并发程序就更难了。 ...

gitchat
05/24
0
0
Java 编程之美:并发编程基础晋级篇

本文来自作者 加多 在 GitChat 上分享 「Java 并发编程之美:并发编程基础晋级篇」 编辑 | Mc Jin 借用 Java 并发编程实践中的话,编写正确的程序并不容易,而编写正常的并发程序就更难了! ...

gitchat
04/18
0
0
关于JVM中long和double的读取原子性

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

Lubby
2015/11/20
0
0
Java并发编程原理与实战二十五:ThreadLocal线程局部变量的使用和原理

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

pony1223
08/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

java大数据转换16进制转10进制

public static void main(String[] args) {String hex = "0xdbf3accc683297cf0000";BigInteger amount = new BigInteger(hex.substring(2), 16);System.out.println(amount);......

任梁荣
昨天
1
0
OSChina 周六乱弹 —— 目测我们程序员丁克的几率不大

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @真Skr小机灵鬼儿:8.13分享Jocelyn Pook/Russian Red的单曲《Loving Strangers》 《Loving Strangers》- Jocelyn Pook/Russian Red 手机党少...

小小编辑
昨天
9
3
TypeScript基础入门 - 函数 - 剩余参数

转载 TypeScript基础入门 - 函数 - 剩余参数 项目实践仓库 https://github.com/durban89/typescript_demo.gittag: 1.2.1 为了保证后面的学习演示需要安装下ts-node,这样后面的每个操作都能...

durban
昨天
1
0
OpenCV边缘检测算子原理总结及实现

1. 拉普拉斯算子 原理:是一种基于图像导数运算的高通线性滤波器。它通过二阶导数来度量图像函数的曲率。 拉普拉斯算子是最简单的各向同性微分算子,它具有旋转不变性。一个二维图像函数的拉...

漫步当下
昨天
0
0
Spring源码阅读——1

开始读Spring源码吧,看再多的技术博客,不如自己看一下~~~~~ Spring源码目前在github中,新版本基于gradle构建。所以阅读源码需要先安装github和gradle。 spring中git地址 1、安装git(略)...

叶枫啦啦
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部