并发程序一个重要方面就是共享数据。

这一点在继承了Thread类或实现了Runnable接口的对象中有着特殊的重要性。

如果你创建了一个实现了Runnable接口的类对象并且用这个对象开启了N个线程对象,那么所有这些线程对象共享同样的属性。

这意味着,如果你再某一线程中修改了属性值,所有其他线程将都能看到并受影响。

有时候,你可能对每个线程拥有自己私有的属性感兴趣。这也正是Java并发API提供的一项机制,

即:thread-local variables 本地线程变量。

本例中,我们会开发一个共享变量程序和一个本地线程变量程序作为对比。

UnsafeTask.java
package com.dylan.thread.ch1.c09.task;

import java.util.Date;
import java.util.concurrent.TimeUnit; /**
* Class that shows the problem generate when some Thread objects
* share a data structure
*
*/
public class UnsafeTask implements Runnable{ /**
* Date shared by all threads
*/
private Date startDate; /**
* Main method of the class. Saves the start date and writes
* it to the console when it starts and when it ends
*/
@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);
} }
Main.java

package com.dylan.thread.ch1.c09.core;

import com.dylan.thread.ch1.c09.task.UnsafeTask;

import java.util.concurrent.TimeUnit;

/**
* Main class of the UnsafeTask. Creates a Runnable task and
* three Thread objects that run it.
*
*/
public class Main { /**
* Main method of the UnsafeTaks. Creates a Runnable task and
* three Thread objects that run it.
* @param args
*/
public static void main(String[] args) {
// Creates the unsafe task
UnsafeTask task=new UnsafeTask(); // Throw three Thread objects
for (int i=0; i<3; i++){
Thread thread=new Thread(task);
thread.start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

运行输出:

Starting Thread: 10 : Mon Apr 30 20:15:01 CST 2018
Starting Thread: 11 : Mon Apr 30 20:15:03 CST 2018
Starting Thread: 12 : Mon Apr 30 20:15:05 CST 2018
Thread Finished: 10 : Mon Apr 30 20:15:05 CST 2018
Thread Finished: 11 : Mon Apr 30 20:15:05 CST 2018

Thread Finished: 12 : Mon Apr 30 20:15:05 CST 2018

可以看到线程结束时间都和最后一个执行结束的线程12的时间一致,说明3个线程的时间变量是共享的。

SafeTask.java
package com.dylan.thread.ch1.c09.task;

import java.util.Date;
import java.util.concurrent.TimeUnit; /**
* Class that shows the usage of ThreadLocal variables to share
* data between Thread objects
*
*/
public class SafeTask implements Runnable { /**
* ThreadLocal shared between the Thread objects
*/
private static ThreadLocal<Date> startDate= new ThreadLocal<Date>() {
protected Date initialValue(){
return new Date();
}
}; /**
* Main method of the class
*/
@Override
public void run() {
// Writes the start date
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();
}
// Writes the start date
System.out.printf("Thread Finished: %s : %s\n",Thread.currentThread().getId(),startDate.get());
} }
SafeMain.java
package com.dylan.thread.ch1.c09.core;

import com.dylan.thread.ch1.c09.task.SafeTask;

import java.util.concurrent.TimeUnit;

/**
* Main class of the example.
*
*/
public class SafeMain { /**
* Main method of the example
* @param args
*/
public static void main(String[] args) {
// Creates a task
SafeTask task=new SafeTask(); // Creates and start three Thread objects for that Task
for (int i=0; i<3; i++){
Thread thread=new Thread(task);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.start();
} } }

运行输出:

Starting Thread: 10 : Mon Apr 30 20:12:45 CST 2018
Starting Thread: 11 : Mon Apr 30 20:12:47 CST 2018
Thread Finished: 10 : Mon Apr 30 20:12:45 CST 2018
Starting Thread: 12 : Mon Apr 30 20:12:49 CST 2018
Thread Finished: 12 : Mon Apr 30 20:12:49 CST 2018
Thread Finished: 11 : Mon Apr 30 20:12:47 CST 2018

可以看到3个线程的时间都不一样,说明没有共享。

Java并发编程实例--9.使用本地线程变量的更多相关文章

  1. java并发编程笔记(三)——线程安全性

    java并发编程笔记(三)--线程安全性 线程安全性: ​ 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现 ...

  2. Java并发编程(您不知道的线程池操作)

    Java并发编程(您不知道的线程池操作) 这几篇博客,一直在谈线程,设想一下这个场景,如果并发的线程很多,然而每个线程如果执行的时间很多的话,这样的话,就会大量的降低系统的效率.这时候就可以采用线程池 ...

  3. 【Java并发编程】之二:线程中断

    [Java并发编程]之二:线程中断 使用interrupt()中断线程 ​ 当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一 ...

  4. java并发编程笔记(七)——线程池

    java并发编程笔记(七)--线程池 new Thread弊端 每次new Thread新建对象,性能差 线程缺乏统一管理,可能无限制的新建线程,相互竞争,有可能占用过多系统资源导致死机或者OOM 缺 ...

  5. java并发编程笔记(五)——线程安全策略

    java并发编程笔记(五)--线程安全策略 不可变得对象 不可变对象需要满足的条件 对象创建以后其状态就不能修改 对象所有的域都是final类型 对象是正确创建的(在对象创建期间,this引用没有逸出 ...

  6. Java并发编程(您不知道的线程池操作), 最受欢迎的 8 位 Java 大师,Java并发包中的同步队列SynchronousQueue实现原理

    Java_并发编程培训 java并发程序设计教程 JUC Exchanger 一.概述 Exchanger 可以在对中对元素进行配对和交换的线程的同步点.每个线程将条目上的某个方法呈现给 exchan ...

  7. 《Java并发编程实战》学习笔记 线程安全、共享对象和组合对象

    Java Concurrency in Practice,一本完美的Java并发参考手册. 查看豆瓣读书 推荐:InfoQ迷你书<Java并发编程的艺术> 第一章 介绍 线程的优势:充分利 ...

  8. Java并发编程(四):线程安全性

    一.定义 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的. 二.线程安 ...

  9. 读书笔记-----Java并发编程实战(一)线程安全性

    线程安全类:在线程安全类中封装了必要的同步机制,客户端无须进一步采取同步措施 示例:一个无状态的Servlet @ThreadSafe public class StatelessFactorizer ...

  10. java并发编程(十五)----(线程池)java线程池简介

    好的软件设计不建议手动创建和销毁线程.线程的创建和销毁是非常耗 CPU 和内存的,因为这需要 JVM 和操作系统的参与.64位 JVM 默认线程栈是大小1 MB.这就是为什么说在请求频繁时为每个小的请 ...

随机推荐

  1. [转帖]History of Unicode Release and Publication Dates

    www.unicode.org For ease of reference, this page collects together information about the dates for v ...

  2. [转帖]harbor 更改网段(docker-compose)

    https://blog.csdn.net/Darkernote/article/details/119390862 问题:harbor 安装后网段冲突 docker-compose 一般安装会创建一 ...

  3. [转帖]logback:logback和slf4j中的:appender、logger、encoder、layout

    (1)appender 1.appender标签是logback配置文件中重要的组件之一.在logback配置文件中使用appender标签进行定义.可 以包含0个或多个appender标签. 2.a ...

  4. [转帖]Linux小知识:sudo su和su的区别

    https://www.cnblogs.com/jiading/p/11717388.html su是申请切换root用户,需要申请root用户密码.有些Linux发行版,例如ubuntu,默认没有设 ...

  5. 初识C语言:掌握未来的编程利器

    ​ 欢迎大家来到贝蒂大讲堂 ​ 养成好习惯,先赞后看哦~ ​ 所属专栏:C语言学习 ​ 贝蒂的主页:Betty's blog 1. C语言是什么 在我们生活中,我们和父母.朋友.老师交流时候使用的就是 ...

  6. linux 53端口占用的原因

    解析 Linux 下 53 端口占用的现象 在 Linux 系统中,端口 53 往往是与域名解析服务(DNS)相关的.本文将详细介绍一个与端口 53 相关的情景,以及如何使用命令行工具来解析和理解这一 ...

  7. 离开页面关闭video标签

    <video src="./play.mp4" id="maskmore_1" controls="controls" autopla ...

  8. 2024-01-27:用go语言,阿里巴巴走进了装满宝藏的藏宝洞。藏宝洞里面有N堆金币, 第i堆金币的总重量和总价值分别是m[i]、v[i], 阿里巴巴有一个承重量为T的背包,但并不一定有办法将全部的

    2024-01-27:用go语言,阿里巴巴走进了装满宝藏的藏宝洞.藏宝洞里面有N堆金币, 第i堆金币的总重量和总价值分别是m[i].v[i], 阿里巴巴有一个承重量为T的背包,但并不一定有办法将全部的 ...

  9. Go 跟踪函数调用链,理解代码更直观

    Go 跟踪函数调用链,理解代码更直观 目录 Go 跟踪函数调用链,理解代码更直观 一.引入 二.自动获取所跟踪函数的函数名 三.增加 Goroutine 标识 四.让输出的跟踪信息更具层次感 五.利用 ...

  10. es从线上库导出数据并导入开发环境

    背景 来了个需求,需要从某个线上es库查询一些数据出来并进行大屏展示.问需求方有没有开发环境的es库,答:没有,说要不直连他们的线上库. 后面想想也行吧,业务方都这么说了,结果开网络的流程被打回了,理 ...