threadlocal_了解ThreadLocal背后的概念

threadlocal

介绍

我知道本地线程,但直到最近才真正使用过它。
因此,我开始深入研究该主题,因为我需要一种传播某些用户信息的简便方法
通过Web应用程序的不同层,而无需更改每个调用方法的签名。

小前提信息

线程是具有自己的调用栈的单个进程。在Java中,每个调用栈有一个线程,或者每个线程有一个调用栈。即使您没有在程序中创建任何新线程,线程也可以在没有您的程序的情况下运行最好的例子是当您仅通过main方法启动一个简单的Java程序时,您没有隐式调用new Thread()。start(),但是JVM为您创建了一个主线程以运行main方法。

主线程是非常特殊的,因为它是所有其他线程都会从中生成的线程,
线程完成后,应用程序结束了它的生命周期。

在Web应用程序服务器中,通常会有一个线程池,因为创建的线程类非常重。所有JEE服务器(Weblogic,Glassfish,JBoss等)都有一个自调整线程池,这意味着线程池会增加或减少需要的时间,因此不会在每个请求上创建线程,而现有的线程将被重用。

了解线程局部

为了更好地理解线程本地,我将展示一种自定义线程本地的非常简单的实现。

package ccs.progest.javacodesamples.threadlocal.ex1;import java.util.HashMap;
import java.util.Map;public class CustomThreadLocal {private static Map threadMap = new HashMap();public static void add(Object object) {threadMap.put(Thread.currentThread(), object);}public static void remove(Object object) {threadMap.remove(Thread.currentThread());}public static Object get() {return threadMap.get(Thread.currentThread());}}

因此,您可以随时在应用程序中调用CustomThreadLocal上的add方法,该方法将在当前映射中将当前线程作为键,并将要与该线程关联的对象作为值。 该对象可能是您想要从当前执行的线程中的任何位置访问的对象,或者它可能是您想要与该线程保持关联并重复使用多次的昂贵对象。
您定义一个ThreadContext类,您在其中拥有要在线程内传播的所有信息。

package ccs.progest.javacodesamples.threadlocal.ex1;public class ThreadContext {private String userId;private Long transactionId;public String getUserId() {return userId;}public void setUserId(String userId) {this.userId = userId;}public Long getTransactionId() {return transactionId;}public void setTransactionId(Long transactionId) {this.transactionId = transactionId;}public String toString() {return 'userId:' + userId + ',transactionId:' + transactionId;}}

现在是时候使用ThreadContext了。

我将启动两个线程,并在每个线程中添加一个新的ThreadContext实例,该实例将保存我想为每个线程传播的信息。

package ccs.progest.javacodesamples.threadlocal.ex1;public class ThreadLocalMainSampleEx1 {public static void main(String[] args) {new Thread(new Runnable() {public void run() {ThreadContext threadContext = new ThreadContext();threadContext.setTransactionId(1l);threadContext.setUserId('User 1');CustomThreadLocal.add(threadContext);//here we call a method where the thread context is not passed as parameterPrintThreadContextValues.printThreadContextValues();}}).start();new Thread(new Runnable() {public void run() {ThreadContext threadContext = new ThreadContext();threadContext.setTransactionId(2l);threadContext.setUserId('User 2');CustomThreadLocal.add(threadContext);//here we call a method where the thread context is not passed as parameterPrintThreadContextValues.printThreadContextValues();}}).start();}
}

注意:
CustomThreadLocal.add(threadContext)是当前线程与ThreadContext实例相关联的代码行
正如您将看到执行此代码一样,结果将是:

userId:User 1,transactionId:1
userId:User 2,transactionId:2

这是怎么可能的,因为我们没有将ThreadContext,userId或trasactionId作为参数传递给printThreadContextValues?

package ccs.progest.javacodesamples.threadlocal.ex1;public class PrintThreadContextValues {public static void printThreadContextValues(){System.out.println(CustomThreadLocal.get());}
}

很简单

从CustomThreadLocal的内部映射调用CustomThreadLocal.get()时,将检索与当前线程关联的对象。

现在,让我们看看何时使用真正的ThreadLocal类的示例。 (上面的CustomThreadLocal类只是为了了解ThreadLocal类背后的原理,该原理非常快并且以最佳方式使用内存)

package ccs.progest.javacodesamples.threadlocal.ex2;public class ThreadContext {private String userId;private Long transactionId;private static ThreadLocal threadLocal = new ThreadLocal(){@Overrideprotected ThreadContext initialValue() {return new ThreadContext();}};public static ThreadContext get() {return threadLocal.get();}public String getUserId() {return userId;}public void setUserId(String userId) {this.userId = userId;}public Long getTransactionId() {return transactionId;}public void setTransactionId(Long transactionId) {this.transactionId = transactionId;}public String toString() {return 'userId:' + userId + ',transactionId:' + transactionId;}
}

如javadoc所述:ThreadLocal实例通常是希望将状态与线程关联的类中的私有静态字段。

package ccs.progest.javacodesamples.threadlocal.ex2;public class ThreadLocalMainSampleEx2 {public static void main(String[] args) {new Thread(new Runnable() {public void run() {ThreadContext threadContext = ThreadContext.get();threadContext.setTransactionId(1l);threadContext.setUserId('User 1');//here we call a method where the thread context is not passed as parameterPrintThreadContextValues.printThreadContextValues();}}).start();new Thread(new Runnable() {public void run() {ThreadContext threadContext = ThreadContext.get();threadContext.setTransactionId(2l);threadContext.setUserId('User 2');//here we call a method where the thread context is not passed as parameterPrintThreadContextValues.printThreadContextValues();}}).start();}
}

调用get时 ,新的ThreadContext实例与当前线程关联,然后将所需值设置为ThreadContext实例。

如您所见,结果与第一组样本相同。

userId:User 1,transactionId:1
userId:User 2,transactionId:2

(这可能是相反的顺序,因此,如果先看到“用户2”,请不要担心)

package ccs.progest.javacodesamples.threadlocal.ex2;public class PrintThreadContextValues {public static void printThreadContextValues(){System.out.println(ThreadContext.get());}
}

ThreadLocal的另一个非常有用的用法是当您有一个非常昂贵的对象的非线程安全实例时的情况。我发现的大多数极性示例是使用SimpleDateFormat(但很快我将提供另一个使用Webservices端口的示例)

package ccs.progest.javacodesamples.threadlocal.ex4;import java.text.SimpleDateFormat;
import java.util.Date;public class ThreadLocalDateFormat {// SimpleDateFormat is not thread-safe, so each thread will have oneprivate static final ThreadLocal formatter = new ThreadLocal() {@Overrideprotected SimpleDateFormat initialValue() {return new SimpleDateFormat('MM/dd/yyyy');}};public String formatIt(Date date) {return formatter.get().format(date);}
}

结论:

线程局部变量有很多用途,这里仅描述两种:(我认为使用最多的)

  • 真正的每线程上下文,例如用户ID或事务ID。
  • 每线程实例以提高性能。

参考: Java代码样本博客中的JCG合作伙伴 Cristian Chiovari 了解了ThreadLocal的概念 。


翻译自: https://www.javacodegeeks.com/2012/07/understanding-concept-behind.html

threadlocal

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

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

相关文章

mysql有nvarchar类型_mysql如何处理varchar与nvarchar类型中的特殊字符

如果你每次建数据表的时候固执的使用varchar,那么你可能会遇到以下的问题: 现在saleUserName的字段类型为varchar(50) update TableNameset saleUserName小覃祝你快乐 where ID87 select * from TableName where ID87 whySaleUserName字段里的文字怎么如…

linux 文件的压缩和打包

在我们的生活中,经常会和朋友、同事、客户发一些文件。为了能够更加快速、高效的将文件传递出去,经常会用到压缩工具。压缩工具通过一定的算法,把数据给尽可能的缩小。这样不仅方便传递、而且可以节省空间。有时候我们需要把一些零散的文件集…

python 爬取svg数据_抓取SVG图表

我试图从以下链接中获取以下svg:我要刮的部分如下:我不需要图表中的文字(只需要图表本身)。但是,我以前从来没有抓取过svg图像,我不确定这是否可能。我环顾四周,但找不到任何有用的python包来直接执行此操作。在我知道…

protected default

protected:主要作用 保护子类 子类可以继承和使用它的成员 其他不行 default:针对本包 类内部本包子类外部包publicOKOKOKOKprotectedOKOKOK defaultOKOK private OK 转载于:https://www.cnblogs.com/love-yangerlei/p/7352337.html

Java 8:再见手册SQL,您好!

大多数用Java编写的应用程序都需要某种形式的数据存储。 在小型应用程序中,这通常是通过使用普通SQL查询的原始JDBC连接来实现的。 另一方面,较大的系统通常使用对象关系映射(ORM)框架来处理数据库通信。 这两种方法都有优点和缺点…

java 鼠标拖动矩形_java – 用鼠标拖动创建矩形,而不是绘制

nb-首先要注意的是,这是使用Java 7完成的,在Java 6中创建透明窗口的方式不同,在更新10之下是不可能的(我相信)基本上,这会创建一个透明窗口,其大小和位置可以覆盖整个虚拟屏幕(也就是说,如果您有多个屏幕,它将覆盖所有虚拟屏幕).然后我使用JPanel作为主要容器来捕获鼠标事件并执…

java实现123n_java三线程交替打印123……n

使用多线程交替打印1--n,a进程打印1,4,7,……(3n1),b进程打印2,7,10,……(3n2),c进程打印3,6,9,……(3n)涉及到多线程的同步,阻塞,wait,notify代码如下Num.javapublic class Num {private int num 0;public Num(int num) {this.num num;}pu…

8月12

MTBF两次故障的时间,时间越长越好。 MTTR两次系统恢复的时间,越短越好 修改完参数后若出现报205的错误,检查路径 控制文件 SQL> show parameter control_files SQL> select * from v$controlfile; 修改路径: $ cd $ORACLE_H…

spring roo_使用Spring Roo进行快速云开发–第2部分:VMware Cloud Foundry

spring rooSpring Roo是在Java平台上提供快速应用程序开发的工具。 我已经解释了何时使用它: http : //www.kai-waehner.de/blog/2011/04/05/when-to-use-spring-roo 。 Spring Roo目前支持两种针对云计算的解决方案:Google App Engine(GAE&a…

this指针 java_彻底理解Java中this指针

每次看到Java中的this指针,总摸不着头绪。在网上看了很多人的讲解,还是不知道this指针到底是什么东西,今天的的这篇日志可以让你看清this到底是谁。(内容摘自:http://www.mathcs.emory.edu/~cheung/Courses/170.2010/Syllabus/03/…

python中的浅拷贝和深拷贝

本篇介绍下python中的深拷贝和浅拷贝,主要从基本类型、类、不可变类型等方面进行介绍。 1.介绍拷贝之前首先应该明白is和的区别,即is表示同一个对象,比较的是值 >>> a 1000 >>> b 1000 >>> a b True >>&…

Spring开发人员知道的一件事

在最近关于(核心)Spring Framework的培训课程中,有人问我:“(Java)Spring开发人员是否应该知道一件事,那应该是什么?” 这个问题使我措手不及。 是的,(核心&a…

mysql匿名事务gtid_MySQL GTID (二)

MySQL GTID 系列之二三.在线将GTID转化为传统模式环境见上篇系列文章关闭GTID,不用停止服务,不影响线上业务3.1 关闭GTID复制,调整为传统复制#SLVAE实例上停止复制STOP SLAVE#SLVAE实例上查看复制的位置SHOW SLAVE STATUS \G# 查看 Master_Log_File 和 Read_Master_Log_Pos对应…

JavaWeb(十七)——JSP中的九个内置对象

一、JSP运行原理 每个JSP 页面在第一次被访问时,WEB容器都会把请求交给JSP引擎(即一个Java程序)去处理。JSP引擎先将JSP翻译成一个_jspServlet(实质上也是一个servlet) ,然后按照servlet的调用方式进行调用。  由于JSP第一次访问…

jrockit_JRockit – JRCMD有用的命令

jrockit自2007年以来,我一直在使用JRockit。我发现它的速度比Hotspot慢,但在诊断和分析问题上总是更好。 从去年夏天开始,我一直在为一家国际电信系统供应商工作。 我们在HP OpenCall融合通信平台之上为电信运营商设计和实施各种产品。 我是开…

java并发问题_并发理论基础:并发问题产生的三大根源

并发问题变幻莫测,一谈到并发就显得非常高深,一般的程序员对于并发问题也是头疼不已,但是随着网络互联越来越普遍,大规模用户访问网站程序也越来越频繁,并发问题又无法避免。在我们解决并发问题前首先要理解产生并发问…

[luoguP1849] [USACO12MAR]拖拉机Tractor(spfa)

传送门 神奇的spfa #include <queue> #include <cstdio> #include <cstring> #include <iostream> #define N 1010 #define max(x, y) ((x) > (y) ? (x) : (y))int n, mx, my; int dis[N][N]; bool map[N][N], vis[N][N]; int dx[4] {0, -1, 0, 1…

在Eclipse上创建JSF / CDI Maven项目

当我在研究JSF和CDI示例时&#xff0c;我认为提及创建JSF和CDI Maven项目所需的步骤会很有用。 您可以找到以下步骤。 工具类 默认情况下&#xff0c;M2E插件随附的Eclipse Luna。 因此&#xff0c;无需自己安装插件。 WildFlye8.x。 从主菜单中选择文件->新建->其他。…

luoguP3690 【模板】Link Cut Tree (动态树)[LCT]

题目背景 动态树 题目描述 给定&#xff2e;个点以及每个点的权值&#xff0c;要你处理接下来的&#xff2d;个操作。操作有&#xff14;种。操作从&#xff10;到&#xff13;编号。点从&#xff11;到&#xff2e;编号。 &#xff10;&#xff1a;后接两个整数&#xff08;&a…

python爬虫多进程_Python爬虫技术--基础篇--多进程

要让Python程序实现多进程(multiprocessing)&#xff0c;我们先了解操作系统的相关知识。Unix/Linux操作系统提供了一个fork()系统调用&#xff0c;它非常特殊。普通的函数调用&#xff0c;调用一次&#xff0c;返回一次&#xff0c;但是fork()调用一次&#xff0c;返回两次&am…