文档章节

线程局部变量的使用

柳哥
 柳哥
发布于 2015/04/26 13:02
字数 758
阅读 540
收藏 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()方法,这个方法用来初始化子线程在线程局部变量中的值,它使用父线程在线程局部变量中的值作为传入参数。

© 著作权归作者所有

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

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

晨曦艾伯特
01/11
0
0
深入理解Python中的ThreadLocal变量(上)

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

selfboot
2016/08/22
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
Linux中的线程局部存储(二)

在 Linux中还有一种更为高效的线程局部存储方法,就是使用关键字thread来定义变量。thread是GCC内置的线程局部存储设施 (Thread-Local Storage),它的实现非常高效,与pthreadkeyt向比较更...

follitude
2016/06/17
14
0

没有更多内容

加载失败,请刷新页面

加载更多

Mac OS X下Maven的安装与配置

Mac OS X 安装Maven: 下载 Maven, 并解压到某个目录。例如/Users/robbie/apache-maven-3.3.3 打开Terminal,输入以下命令,设置Maven classpath $ vi ~/.bash_profile 添加下列两行代码,之后...

TonyStarkSir
今天
3
0
关于编程,你的练习是不是有效的?

最近由于工作及Solution项目的影响,我在重新学习DDD和领域建模的一些知识。然后,我突然就想到了这个问题,以及我是怎么做的? 对于我来说,提升技能的项目会有四种: 纯兴趣驱动的项目。即...

问题终结者
今天
3
0
打开eclipse出现an error has occurred see the log file

解决方法: 1,打开eclipse安装目录下的eclipse.ini文件; 2,打开的文本文件最后添加一行 --add-modules=ALL-SYSTEM 3,保存重新打开Eclipse。...

任梁荣
昨天
4
0
搞定Northwind示例数据库,无论哪个版本的SQLServer都受用

Northwind数据库 从这里可以找到突破口: http://social.msdn.microsoft.com/Forums/zh-CN/Vsexpressvb/thread/8490a1c6-9018-40c9-aafb-df9f79d29cde 下面是MSDN: http://msdn2.microsoft......

QQZZFT
昨天
1
0
mysql主从同步,安装配置操作

准备 两台mysql服务,我这里准备了如下: 主库:192.168.176.128 从库:192.168.176.131 如何在Linux上安装mysql服务,请看https://blog.csdn.net/qq_18860653/article/details/80250499 操作...

小致dad
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部