ThreadLocal线程范围内的共享变量

模拟ThreadLocal类实现:线程范围内的共享变量,每个线程只能访问他自己的,不能访问别的线程。

package com.ljq.test.thread;import java.util.HashMap;
import java.util.Map;
import java.util.Random;/*** 线程范围内的共享变量* * 三个模块共享数据,主线程模块和AB模块* * @author Administrator* */
public class ThreadScopeShareData {// 准备共享的数据private static int data = 0;// 存放各个线程对应的数据private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();public static void main(String[] args) {// 启动两个线程for (int i = 0; i < 2; i++) {new Thread(new Runnable() {@Overridepublic void run() {// 现在当前线程中修改一下数据,给出修改信息int data = new Random().nextInt();// 将线程信息和对应数据存储起来
                    threadData.put(Thread.currentThread(), data);System.out.println(Thread.currentThread().getName() + " has put data :" + data);new A().get();new B().get();}}).start();}}static class A {public void get() {int data = threadData.get(Thread.currentThread());System.out.println("A from " + Thread.currentThread().getName()+ " get data :" + data);}}static class B {public void get() {int data = threadData.get(Thread.currentThread());System.out.println("B from " + Thread.currentThread().getName()+ " get data :" + data);}}
}

运行结果:


ThreadLocal的作用和目的:
用于实现线程内的数据共享,即对于相同的程序代码,多个模块在同一个线程中运行时要共享一份数据,而在另外线程中运行时又共享另外一份数据。

每个线程调用全局ThreadLocal对象的set方法,就相当于往其内部的map中增加一条记录,key分别是各自的线程,value是各自的set方法传进去的值。在线程结束时可以调用ThreadLocal.clear()方法,这样会更快释放内存,不调用也可以,因为线程结束后也可以自动释放相关的ThreadLocal变量。

ThreadLocal的应用场景:
订单处理包含一系列操作:减少库存量、增加一条流水台账、修改总账,这几个操作要在同一个事务中完成,通常也即同一个线程中进行处理,如果累加公司应收款的操作失败了,则应该把前面的操作回滚,否则,提交所有操作,这要求这些操作使用相同的数据库连接对象,而这些操作的代码分别位于不同的模块类中。

银行转账包含一系列操作: 把转出帐户的余额减少,把转入帐户的余额增加,这两个操作要在同一个事务中完成,它们必须使用相同的数据库连接对象,转入和转出操作的代码分别是两个不同的帐户对象的方法。

例如Strut2的ActionContext,同一段代码被不同的线程调用运行时,该代码操作的数据是每个线程各自的状态和数据,对于不同的线程来说,getContext方法拿到的对象都不相同,对同一个线程来说,不管调用getContext方法多少次和在哪个模块中getContext方法,拿到的都是同一个。

实验案例:定义一个全局共享的ThreadLocal变量,然后启动多个线程向该ThreadLocal变量中存储一个随机值,接着各个线程调用另外其他多个类的方法,这多个类的方法中读取这个ThreadLocal变量的值,就可以看到多个类在同一个线程中共享同一份数据。

实现对ThreadLocal变量的封装,让外界不要直接操作ThreadLocal变量。
对基本类型的数据的封装,这种应用相对很少见。
对对象类型的数据的封装,比较常见,即让某个类针对不同线程分别创建一个独立的实例对象。

package com.ljq.test.thread;import java.util.Random;/*** ThreadLocal类及应用技巧* * 将线程范围内共享数据进行封装,封装到一个单独的数据类中,提供设置获取方法* 将该类单例化,提供获取实例对象的方法,获取到的实例对象是已经封装好的当前线程范围内的对象*/
public class ThreadLocalTest {private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();//private static ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>();public static void main(String[] args) {for(int i=0;i<2;i++){new Thread(new Runnable(){@Overridepublic void run() {int data = new Random().nextInt();System.out.println(Thread.currentThread().getName() + " has put data :" + data);x.set(data);/*					MyThreadScopeData myData = new MyThreadScopeData();myData.setName("name" + data);myData.setAge(data);myThreadScopeData.set(myData);*/MyThreadScopeData.getThreadInstance().setName("name" + data);MyThreadScopeData.getThreadInstance().setAge(data);new A().get();new B().get();}}).start();}}//使用获取到的线程范围内的对象实例调用相应方法static class A{public void get(){int data = x.get();System.out.println("A from " + Thread.currentThread().getName() + " get data :" + data);/*			MyThreadScopeData myData = myThreadScopeData.get();System.out.println("A from " + Thread.currentThread().getName() + " getMyData: " + myData.getName() + "," + myData.getAge());*/MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();System.out.println("A from " + Thread.currentThread().getName() + " getMyData: " + myData.getName() + "," + myData.getAge());}}//使用获取到的线程范围内的对象实例调用相应方法static class B{public void get(){int data = x.get();			System.out.println("B from " + Thread.currentThread().getName() + " get data :" + data);MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();System.out.println("B from " + Thread.currentThread().getName() + " getMyData: " + myData.getName() + "," + myData.getAge());			}		}
}class MyThreadScopeData {// 单例private MyThreadScopeData() {}// 提供获取实例方法,不加synchronized关键字表示线程各拿各自的数据,互不干扰public static/* synchronized */MyThreadScopeData getThreadInstance() {// 从当前线程范围内数据集中获取实例对象MyThreadScopeData instance = map.get();if (instance == null) {instance = new MyThreadScopeData();map.set(instance);}return instance;}// 将实例对象存入当前线程范围内数据集中private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}

xxx
xxxxxxx
xxx
xxx
xxx

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/544896.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java LineNumberReader reset()方法及示例

LineNumberReader类的reset()方法 (LineNumberReader Class reset() method) reset() method is available in java.io package. reset()方法在java.io包中可用。 reset() method is used to reset this LineNumberReader stream to the position of the most recent mark was …

Html 按钮button加超链接

http://blog.csdn.net/maxracer/article/details/6409437 1.页面转向新的页面: <input type"button" οnclick"window.location.href(连接)"> 2.需要打开一个新的页面进行转向: <input type"button" οnclick"window.open(连接)&…

Java中操作Excel的3种方法,太好用了!

一、介绍在平时的业务系统开发中&#xff0c;少不了需要用到导出、导入excel功能&#xff0c;今天我们就一起来总结一下&#xff0c;如果你正为此需求感到困惑&#xff0c;那么阅读完本文&#xff0c;你一定会有所收获&#xff01;二、poi大概在很久很久以前&#xff0c;微软的…

代理服务器Tengine的研究与测试

代理服务器Tengine的研究与测试一、Tengine介绍1.首先要知道什么Nginx1)Nginx&#xff08;发音同 engine x&#xff09;是一款轻量级的Web 服务器&#xff0f;反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#xff0c;并在一个BSD-like 协议下发行。由…

Java Integer类toString()方法与示例

Syntax: 句法&#xff1a; public String toString();public static String toString(int value);public static String toString(int value, int radixs);整数类toString()方法 (Integer class toString() method) toString() method is available in java.lang package. toS…

不错!SpringBoot发布Jar包优化瘦身指南!

概要说明随着Spring Boot的流行&#xff0c;大家体验到只需构建输出一个jar文件&#xff0c;然后只需一个java -jar命令就能部署运行应用的爽快。常见一些单体应用随着项目规模的扩展单个jar文件的大小越来越大&#xff0c;动辄两三百MB。如果再引入微服务架构&#xff0c;动辄…

Jsp中使用数据库连接池

1. 在tomcat服务器目录下面的conf中找到一个叫Context.xml的配置文件&#xff0c;在其中加入以下代码 <Resource name"jdbc/books"auth"Container" type"javax.sql.DataSource"maxActive"100"maxIdle"30"maxWait"10…

Java IdentityHashMap values()方法与示例

IdentityHashMap类values()方法 (IdentityHashMap Class values() method) values() method is available in java.util package. values()方法在java.util包中可用。 values() method is used to return the values exist in this IdentityHashMap to be viewed in a Collecti…

CountDownLatch:别浪,等人齐再团!

一入王者深似海&#xff0c;从此对象是路人。哈喽观众老爷们大家好&#xff0c;我是战神吕布字奉先&#xff0c;今天给大家来一部吕布的教学视频&#xff01;咳咳&#xff0c;不对。大家好&#xff0c;我是磊哥&#xff0c;今天给大家来一篇 CountDownLatch 的文章。在开始之前…

ASP在 Web.config 中创建数据库连接字符串

在 Web.config 中创建数据库连接串我们需要在网站的配置文件中增加一些行&#xff0c;以便 Entity Framework 知道如何连接到我们的数据库&#xff0c;双击Web.config 文件。 卷到文件的最后&#xff0c;然后增加一个 <connectionStrings> 的配置节&#xff0c;如何所示&…

easyUI layout 中使用tabs+iframe解决请求两次方法

demo中的事例在加载tab页面时是 1 function createFrame(url) {2 var s <iframe name"iframepanel" scrolling"no" frameborder"0" src" url " style"width:100%;height:100%;"></iframe>;3 …

jQuery 的选择器 元素选择器

>> 转&#xff1a;http://www.cnblogs.com/onlys/articles/jQuery.htmljQuery 的选择器可谓之强大无比&#xff0c;这里简单地总结一下常用的元素查找方法 $("#myELement") 选择id值等于myElement的元素&#xff0c;id值不能重复在文档中只能有一个id值是my…

Java FilterInputStream skip()方法与示例

FilterInputStream类skip()方法 (FilterInputStream Class skip() method) skip() method is available in java.io package. skip()方法在java.io包中可用。 skip() method is used to skip the given number of bytes of data from this FilterInputStream. skip()方法用于从…

附彩蛋|Spring Security 竟然故意延长登录时间?知道真相的我惊呆了!

2011年12月21日&#xff0c;有人在网络上公开了一个包含600万个CSDN用户资料的数据库&#xff0c;数据全部为明文储存&#xff0c;包含用户名、密码以及注册邮箱。事件发生后CSDN在微博、官方网站等渠道发出了声明&#xff0c;解释说此数据库系2009年备份所用&#xff0c;因不明…

DirectX 矩阵

基础&#xff1a; 下标&#xff1a;第一个下标为该元素所在行的索引&#xff0c;第二个下标为该元素所在列的索引。如下图所示 行向量和列向量&#xff1a;只有单行的向量称为行向量&#xff0c;只有单列的称之为列向量。 相等 维数和元素都相等 数乘(与标量相乘) 每一个元素与…

div 图片滚动 / 文字滚动

今天研究了一下图片滚动&#xff0c;网上有很多可以使用的例子&#xff0c;所以先是找了一个用的是表格布局的&#xff0c;如下&#xff1a;<!DOCTYPE html> <html xmlns"http://www.w3.org/1999/xhtml"> <head><meta http-equiv"Content-…

为什么阿里内部不允许用Executors创建线程池?

来源&#xff1a;cnblogs.com/zjfjava/p/11227456.html1. 通过Executors创建线程池的弊端在创建线程池的时候&#xff0c;大部分人还是会选择使用Executors去创建。下面是创建定长线程池&#xff08;FixedThreadPool&#xff09;的一个例子&#xff0c;严格来说&#xff0c;当使…

Java FilePermission暗含()方法与示例

FilePermission类implies()方法 (FilePermission Class implies() method) implies() method is available in java.io package. implies()方法在java.io包中可用。 implies() method is used to check whether this FilePermission implies the given permission (perm) or no…

填充

1. $number 68 {0:d7} -f $number2. $number1 68$number1.PadLeft(7,0)转载于:https://www.cnblogs.com/IvanChen/p/4492976.html

RabbitMQ中7种消息队列和保姆级代码演示!

blog.csdn.net/qq_32828253/article/details/110450249七种模式介绍与应用场景简单模式&#xff08;Hello World&#xff09;做最简单的事情&#xff0c;一个生产者对应一个消费者&#xff0c;RabbitMQ相当于一个消息代理&#xff0c;负责将A的消息转发给B应用场景&#xff1a;…