文档章节

并发编程实战 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并发】-----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面试:投行的15个多线程和并发面试题

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

ImportNew
08/23
0
0
Java 编程之美:并发编程高级篇之一

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

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

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

gitchat
04/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring中static变量不能@value注入的原因

今天本想使用@Value的方式使类中的变量获得yml文件中的配置值,然而一直失败,获得的一直为null。 类似于这样写的。 public class RedisShardedPool { private static ShardedJedisPool pool...

钟然千落
今天
2
0
CentOS7防火墙firewalld操作

firewalld Linux上新用的防火墙软件,跟iptables差不多的工具。 firewall-cmd 是 firewalld 的字符界面管理工具,firewalld是CentOS7的一大特性,最大的好处有两个:支持动态更新,不用重启服...

dingdayu
今天
1
0
关于组件化的最初步

一个工程可能会有多个版本,有国际版、国内版、还有针对各种不同的渠道化的打包版本、这个属于我们日常经常见到的打包差异化版本需求。 而对于工程的开发,比如以前的公司,分成了有三大块业...

DannyCoder
今天
2
0
Spring的Resttemplate发送带header的post请求

private HttpHeaders getJsonHeader() { HttpHeaders headers = new HttpHeaders(); MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8"); ......

qiang123
昨天
3
0
Spring Cloud Gateway 之 Only one connection receive subscriber allowed

都说Spring Cloud Gateway好,我也来试试,可是配置了总是报下面这个错误: java.lang.IllegalStateException: Only one connection receive subscriber allowed. 困扰了我几天的问题,原来...

ThinkGem
昨天
38
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部