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

这一点在继承了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. .NET技术面试题系列(2) -sql server数据库优化规范

    1.数据库优化规范 a.索引 每个表格都要求建立主键,主键上不一定需要强制建立聚集索引. 聚集索引,表中存储的数据按照索引的顺序存储,即逻辑顺序决定了表中相应行的物理顺序,因此聚集索引的字段值应是不会 ...

  2. Oracle 高低水位线的学习

    Oracle 高低水位线的学习 背景 最近产品的一些脚本会大量的给一些流程表里面插入数据 因为只是一个流程相关没有时序查询的需求 所以数据量挺大, 但是按照石时间戳删除非常麻烦. 自己执行过多次del ...

  3. 【转帖】nginx变量使用方法详解-4

    https://www.diewufeiyang.com/post/578.html 在设置了"取处理程序"的情况下,Nginx 变量也可以选择将其值容器用作缓存,这样在多次读取变 ...

  4. VM PowerCli的简单安装和使用学习

    1. Win10 上面安装 下载 zip包并且进行安装 win10 已经带了powershell 安装比较简单, 只不过安装时会提示 powershell的权限有问题需要打开powershell 执行 ...

  5. Oracle 以及 达梦数据库简单查询所有表行数的存储过程

    1. 今天有一个场景需要查询一个数据库实例下面所有的表的行数. 本来想查询 user_tables 视图 但是发现 这个视图里面 达梦数据库 里面存的是null的.. 百度之后发现一个解决方案是 使用 ...

  6. 兼容微信支付宝抖音小程序的工具推荐!还能将小程序搬到自己的app里面

    事情的起因是这样的. 之前在微信.支付宝和抖音开放平台都上架了自己的小程序,虽然几个平台有自己的开发标准,但是都是基于 JavaScript 这种已经被广泛使用的编程语言进行开发的,对于开发者而言学习 ...

  7. Solon 框架启动为什么特别快?

    思来想去!可能与 Solon 容器的独立设计有一定关系. 1.Solon 注解容器的运行特点 有什么注解要处理的(注解能力被规范成了四种),提前注册登记 全局只扫描一次,并在扫描过程中统一处理注解相关 ...

  8. CE修改器入门:寻找指针基址

    上一步阐述了如何使用代码替换功能对付变化位置的数据地址,但这种方法往往不能达到预期的效果,所以我们需要学习如何利用指针,在本关的 Tutorial.exe 窗口下面有两个按钮,一个会改变数值,另一个不 ...

  9. UDP通信 [补档-2023-07-22]

    UDP通信 6-1 简介 ​ UDP通信是面向无链接的,不稳定,不可靠,不安全的一种通信方式.TCP在通信前发送方会向接收方进行三次握手链接,然后确认双方链接后才会进行数据传输,最后四次挥手保证链接关 ...

  10. 高精度模板 大数加大数,可变数组vector实现

    vector<int> Add(vector<int>& A, vector<int>& B)//采用引用传入vector,避免将其全部复制传值,使 ...