线程管理(九)使用本地线程变量

校对:方腾飞

使用本地线程变量

并发应用的一个关键地方就是共享数据。这个对那些扩展Thread类或者实现Runnable接口的对象特别重要。

如果你创建一个类对象,实现Runnable接口,然后多个Thread对象使用同样的Runnable对象,全部的线程都共享同样的属性。这意味着,如果你在一个线程里改变一个属性,全部的线程都会受到这个改变的影响。

有时,你希望程序里的各个线程的属性不会被共享。 Java 并发 API提供了一个很清楚的机制叫本地线程变量。

在这个指南中, 我们将开发一个程序,这个程序用来描述在第一段话里的问题,和另一个程序使用本地线程变量机制解决这个问题。

准备

指南中的例子是使用Eclipse IDE 来实现的。如果你使用Eclipse 或者其他的IDE,例如NetBeans, 打开并创建一个新的java项目。

怎么做呢

按照这些步骤来实现下面的例子:

1.   首先,我们来实现一个程序含有上述的问题。

创建一个类名为 UnsafeTask 并实现 Runnable 接口。 声明一个 private java.util.Date 属性.

1 public class UnsafeTask implements Runnable{
2 private Date startDate;

2. 实现UnsafeTask 对象的run() 方法,此方法会初始 startDate 属性, 把值写入控制台,随机休眠一段时间,最后在写入startDate 属性。

01 @Override
02 public void run() {
03 startDate=new Date();
04 System.out.printf("Starting Thread: %s : %s\n",Thread. currentThread().getId(),startDate);
05 try {
06 TimeUnit.SECONDS.sleep( (int)Math.rint(Math.random()*10));
07 } catch (InterruptedException e) {
08 e.printStackTrace();
09 }
10 System.out.printf("Thread Finished: %s : %s\n",Thread. currentThread().getId(),startDate);
11 }

3.   现在,来实现这个有问题例子的主类。创建一个 Main  类和 main() 方法. 此方法会创建一个 UnsafeTask 类的对象,并开始3个线程使用这个对象,每个线程间休眠2秒。

01 public class Core {
02 public static void main(String[] args) {
03 UnsafeTask task=new UnsafeTask();
04  for (int i=0; i<10; i++){
05 Thread thread=new Thread(task);
06 thread.start();
07 try { TimeUnit.SECONDS.sleep(2);
08 } catch (InterruptedException e) {
09 e.printStackTrace();
10 }
11 }
12 }
13 }

4.   在以下的裁图,你可以发现这个程序的执行结果。每个线程有着不同的开始时间,但是全部都有相同的结束时间。

5.   如在之前提到的, 我们会使用本地线程变量机制来解决这个问题。

6.   创建一个类名为 SafeTask a一定实现 Runnable 接口。

1 public class SafeTask implements Runnable {

7.   声明 ThreadLocal<Date> 类对象。此对象有隐含实现了 initialValue()方法. 此方法会返回真实日期。

1 private static ThreadLocal<Date> startDate= new ThreadLocal<Date>() {
2 protected Date initialValue(){
3 return new Date();
4 }
5 };

8.   实现run()方法。它和 UnsafeClass的run() 方法功能一样,只是改变了属性的访问方式。

01 @Override
02 public void run() {
03   System.out.printf("Starting Thread: %s : %s\n",Thread.currentThread().getId(),startDate.get());
04 try {
05   TimeUnit.SECONDS.sleep((int)Math.rint(Math.random()*10));
06 } catch (InterruptedException e) {
07 e.printStackTrace();
08 }
09 System.out.printf("Thread Finished: %s : %s\n",Thread.currentThread().getId(),startDate.get());
10 }

9.    这个例子的主类跟不安全例子一样,把名字改成 Runnable 类。

10. 运行例子并分析不同处。

它是怎么工作的

在下面的截图里,你可以看到线程安全模式下程序运行的结果。现在3个 Thread 对象都有他们自己的startDate 属性值。看下图:

本地线程变量为每个使用这些变量的线程储存属性值。可以用 get() 方法读取值和使用 set() 方法改变值。 如果第一次你访问本地线程变量的值,如果没有值给当前的线程对象,那么本地线程变量会调用 initialValue() 方法来设置值给线程并返回初始值。

更多

本地线程类还提供 remove() 方法,删除存储在线程本地变量里的值。

Java 并发 API 包括 InheritableThreadLocal 类提供线程创建线程的值的遗传性 。如果线程A有一个本地线程变量,然后它创建了另一个线程B,那么线程B将有与A相同的本地线程变量值。 你可以覆盖 childValue() 方法来初始子线程的本地线程变量的值。 它接收父线程的本地线程变量作为参数。 

时间: 2024-11-02 08:05:09

线程管理(九)使用本地线程变量的相关文章

Java并发编程示例(九):本地线程变量的使用_java

共享数据是并发程序最关键的特性之一.对于无论是继承Thread类的对象,还是实现Runnable接口的对象,这都是一个非常周重要的方面. 如果创建了一个实现Runnable接口的类的对象,并使用该对象启动了一系列的线程,则所有这些线程共享相同的属性.换句话说,如果一个线程修改了一个属性,则其余所有线程都会受此改变的影响. 有时,我们更希望能在线程内单独使用,而不和其他使用同一对象启动的线程共享.Java并发接口提供了一种很清晰的机制来满足此需求,该机制称为本地线程变量.该机制的性能也非常可观.

线程管理(一)线程的创建和运行

线程的创建和运行 在这个指南中,我们将学习如何在Java程序中创建和运行线程.与每个Java语言中的元素一样,线程是对象.在Java中,我们有2个方式创建线程: 通过直接继承thread类,然后覆盖run()方法. 构建一个实现Runnable接口的类, 然后创建一个thread类对象并传递Runnable对象作为构造参数 在这个指南中,我们将使用第二种方法来制作一个简单的程序,它能创建和运行10个线程.每一个线程能计算和输出1-10以内的乘法表. 准备 指南中的例子是使用Eclipse IDE

线程管理(十)线程组

线程组 Java并发 API里有个有趣的方法是把线程分组.这个方法允许我们按线程组作为一个单位来处理.例如,你有一些线程做着同样的任务,你想控制他们,无论多少线程还在运行,他们的状态会被一个call 中断. Java 提供 ThreadGroup 类来组织线程. ThreadGroup 对象可以由 Thread 对象组成和由另外的 ThreadGroup 对象组成,生成线程树结构. 在这个指南中, 我们将开发一个简单的例子来学习 ThreadGroup 对象.我们有 10 个随机时间休眠的线程

线程管理(三)线程的中断

线程的中断 一个多个线程在执行的Java程序,只有当其全部的线程执行结束时(更具体的说,是所有非守护线程结束或者某个线程调用System.exit()方法的时候),它才会结束运行.有时,你需要为了终止程序而结束一个线程,或者当程序的用户想要取消某个Thread对象正在做的任务. Java提供中断机制来通知线程表明我们想要结束它.中断机制的特性是线程需要检查是否被中断,而且还可以决定是否响应结束的请求.所以,线程可以忽略中断请求并且继续运行. 在这个指南中, 我们将开发一个程序,它创建线程,然后在

线程管理(五)线程的睡眠和恢复

线程的睡眠与恢复 有时, 你会感兴趣在一段确定的时间内中断执行线程.例如, 程序的一个线程每分钟检查反应器状态.其余时间,线程什么也不做.在这段时间,线程不使用任何计算机资源.过了这段时间,当JVM选择它时,线程会准备好继续执行.为达此目的,你可以使用Thread类的 sleep() 方法 .此方法接收一个整数作为参数,表示线程暂停运行的毫秒数. 在调用sleep() 方法后,当时间结束时,当JVM安排他们CPU时间,线程会继续按指令执行, 另一种可能是使用一个有TimeUnit列举元素的sle

Android线程管理之ActivityThread

ActivityThread功能 它管理应用进程的主线程的执行(相当于普通Java程序的main入口函数),并根据AMS的要求(通过IApplicationThread接口,AMS为Client.ActivityThread.ApplicationThread为Server)负责调度和执行activities.broadcasts和其它操作. 在Android系统中,在默认情况下,一个应用程序内的各个组件(如Activity.BroadcastReceiver.Service)都会在同一个进程(

Linux线程管理必备:解析互斥量与条件变量的详解_C 语言

   做过稍微大一点项目的人都知道,力求程序的稳定性和调度的方便,使用了大量的线程,几乎每个模块都有一个专门的线程处理函数.而互斥量与条件变量在线程管理中必不可少,任务间的调度几乎都是由互斥量与条件变量控制.互斥量的实现与进程中的信号量(无名信号量)是类似的,当然,信号量也可以用于线程,区别在于初始化的时候,其本质都是P/V操作.编译时,记得加上-lpthread或-lrt哦.    有关进程间通信(消息队列)见:进程间通信之深入消息队列的详解 一.互斥量 1. 初始化与销毁:    对于静态分

一个简单的线程管理方式。

文章来源: www.17173.com 周末,总是有点那么的无聊.闲来没事,想想每次自己要进行多线程编程时的痛苦,也并借机考虑设计了一个简单的线程管理方式.      没什么好说的,首先想想线程的创建,每次都要CreateThread,传递一堆的参数,还得没事查查MSDN,唉,效率低啊.反正,对于我来说,线程基本都是缺省优先级.缺省安全的.不如把这些一起封装了.     不多说,C++不用对象机制用什么?顺便借鉴一下java.来个实际线程就是run,启动采用start. class thread

《多核与GPU编程:工具、方法及实践》----3.8 动态线程管理与静态线程管理

3.8 动态线程管理与静态线程管理 3.2.3.1节介绍过,Qt管理一组就绪的线程池,不需要操作系统来分配和初始化新线程实体.尽管创建线程的开销较之创建进程的开销要小几个量级,但它仍然是较为耗时的,特别是当线程需要在运行时动态生成时.一个经典的粒子是监听请求和分配线程进行服务的并发Web或者数据库服务器.在这种情况下线程可以从一个空闲线程库中选取并重用,而不是为每一个请求创建一个新的线程.QThreadPool类提供的功能正是这种线程库. 本节将要介绍如何利用QThreadPool,以及如何创建