文档章节

线程局部变量的使用

柳哥
 柳哥
发布于 2015/04/26 13:02
字数 758
阅读 554
收藏 9

共享数据是并发程序最核心的问题之一,对于继承了Thread类或者实现了Runnable接口的对象来说尤其重要。如果创建的对象是实现了Runnable接口的类的实例,用它作为传入参数创建多个线程对象并启动这些线程,那么所有的线程将共享相同的属性。也就是说,如果你在一个线程中改变了一个属性,所有线程都会被这个改变影响。

在某种情况下,这个对象的属性不需要被所有线程共享。Java并发API提供了一个干净的机制,即线程局部变量(Thread-Local Variable),其具有很好的性能。

这里我们将创建两个程序:第一个具有刚才提到的问题。另一个使用线程局部变量机制解决了这个问题。

第一个示例,显示共享才生的问题:

package concurrency;

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

public class Main3 {
    public static void main(String[] args) {
        UnsafeTask task = new UnsafeTask();
        for(int i=0; i<10;i++){
            Thread thread = new Thread(task);
            thread.start();
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class UnsafeTask implements Runnable{
    private Date startDate;
    @Override
    public void run() {
        startDate = new Date();
        System.out.printf("Starting Thread:  %s  :  %s\n", Thread.currentThread().getId(),startDate);
        try {
            TimeUnit.SECONDS.sleep((int)Math.rint(Math.random()*10));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("Thread Finished:  %s  :  %s\n", Thread.currentThread().getId(),startDate);
    }
}

第二个示例,例用线程局部变量解决第一个示例中的问题:

package concurrency;

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

public class Main4 {
    public static void main(String[] args) {
        SafeTask task = new SafeTask();
        for(int i=0; i<10;i++){
            Thread thread = new Thread(task);
            thread.start();
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class  SafeTask implements Runnable{
    private static ThreadLocal<Date> startDate = new ThreadLocal<Date>(){
        protected Date initialValue(){
            return new Date();
        }
    };
    @Override
    public void run() {
        System.out.printf("Starting Thread:  %s  :  %s\n", Thread.currentThread().getId(),startDate.get());
        try {
            TimeUnit.SECONDS.sleep((int)Math.rint(Math.random()*10));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("Thread Finished:  %s  :  %s\n", Thread.currentThread().getId(),startDate.get());
    }
}

声明一个ThreadLocal<Date>对象。Date的对象是在initialValue()方法中隐式实现的,这个方法将返回当前日期。线程局部变量分别为每个线程存储了各自的属性值,并提供给每个线程使用。你可以使用get()方法读取这个值,并用set()方法设置这个值。如果线程是第一次访问线程局部变量,线程局部变量可能还没有为它存储值,这个时候initialValue()方法就会被调用,并且返回当前的时间值。

线程局部变量也提供了remove()方法,用来为访问这个变量的线程删除已经存储的值。Java并发API包含了InheritableThreadLocal类,如果一个线程是从其他某个线程中创建的,这个类将提供继承的值。如果一个线程A在线程局部变量已有值,当它创建其他某个线程B时,线程B的线程局部变量将跟线程A是一样的。你可以覆盖childValue()方法,这个方法用来初始化子线程在线程局部变量中的值,它使用父线程在线程局部变量中的值作为传入参数。

© 著作权归作者所有

共有 人打赏支持
柳哥
粉丝 206
博文 405
码字总数 347782
作品 0
杭州
技术主管
私信 提问
JAVA中ThreadLocal用法介绍

概述 看名字好像是一个Thread的实现,其实并不是这样的,ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物...

晨曦艾伯特
2018/01/11
0
0
java ThreadLocal

JDKAPI 解释: 该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其get或set方法)的每个线程都有自己的局部变量,它独立于初始化变量的副本...

smallsun512
2013/06/26
0
0
Linux中的线程局部存储(一)

在 Linux系统中使用C/C++进行多线程编程时,我们遇到最多的就是对同一变量的多线程读写问题,大多情况下遇到这类问题都是通过锁机制来处理,但这对 程序的性能带来了很大的影响,当然对于那些...

follitude
2016/06/17
16
0
深入理解Python中的ThreadLocal变量(上)

我们知道多线程环境下,每一个线程均可以使用所属进程的全局变量。如果一个线程对全局变量进行了修改,将会影响到其他所有的线程。为了避免多个线程同时对变量进行修改,引入了线程同步机制,...

selfboot
2016/08/22
0
0
JDK源码学习之ThreadLocal

ThreadLocal是什么 早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。 Th...

孟飞阳
2016/07/05
59
0

没有更多内容

加载失败,请刷新页面

加载更多

解决各浏览器向url中传中问参数的问题

https://www.cnblogs.com/godtrue/p/4333262.html 后台的处理代码 public static String getUrlnewName( String oldName) {String newName = "";try {String agent = inv.get......

踏破铁鞋无觅处
41分钟前
1
0
微信支付携带证书请求

package utils.wechat; import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.security.KeyStore; import javax.net.ssl.SSLContext;......

猿神出窍
49分钟前
2
0
1093 - You can't specify target table 'xxx' for update in FROM clause, Time: 0.002000s

1093 - You can't specify target table 'xxx' for update in FROM clause, Time: 0.002000s 根据结果集在b_order_copy1 表中删除 DELETE FROM b_order_copy1 WHERE Id in ( SELECT Id FRO......

lwenhao
50分钟前
1
0
JavaScriptCore全面解析

本文由云+社区发表 作者:殷源,专注移动客户端开发,微软Imagine Cup中国区特等奖获得者 JavaScript越来越多地出现在我们客户端开发的视野中,从ReactNative到JSpatch,JavaScript与客户端相...

腾讯云加社区
54分钟前
1
0
Jmeter参数的AES加密使用

在Jmeter日常实践中,大家应该都遇到过接口传参需要加密的情况。以登陆为例,用户名和密码一般都需要进行加密传输,在服务端再进行解密,这样安全系数会更高,但在使用jmeter进行接口测试的时...

程序猿拿Q
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部