您的位置:首页 > 编程语言 > Java开发

有必要澄清一下究竟TLS(or java's thread local)的作用是什么

2015-03-14 00:50 267 查看
转自:http://www.oschina.net/question/735298_101939

OSCHINA上看到了好几篇帖子在介绍Java的ThreadLocal类,但是,说到该类的作用是,竟然一致的都和线程的同步/互斥扯上关系,将其划作与Synchronized功能一样的,用来解决多线程间并发访问共享资源的一种方式。 觉得实在有必要澄清一下,下面汇总了我回的一些内容,作为澄清。

首先Java的ThreadLocal本质上就是TLS(Thread Local Storage),所以TLS的作用究竟是什么那?

不要由于java混淆了本质,其实就是TLS的概念,去问问搞linux的前辈,TLS的目的是为了线程同步和互斥?完全不同的概念
简直误人子弟,我在OSCHINA看到两篇关于ThreadLocal的文档了,都是说“ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题”。 TLS(Thread Local Storage) 是为了解决线程安全和并发访问共享资源的目的?!
线程互斥技术是为了解决,多个线程间共享的,大家都要访问和读写的资源,如何在线程并发时不会有问题,典型的打印机问题!注意,这里的资源,是需要在多个线程间共享的!

而TLS究竟是解决什么问题那? TLS解决了这样一个需求,就是希望在一个/每个线程的线程上下文/环境下执行的任何实体(函数,组件等)内,都能访问某一个变量。 那么很明显,这个变量是需要做成全局的,但是,普通全局的会污染别的线程。所以,此时需要TLS。 举个最简单的例子,假设我的程序会连续启动6个线程去创建文件,线程代码是完全一样的。那么,我就可以使用TLS来记录线程上下文中的文件句柄。此时,我使用一致的文件操作代码,却能保证不管在任何实体中操作的文件句柄,都自动的是当前线程下的打开文件的文件句柄

TLS更多的是用来存储线程上下文相关的信息,使得在一致的代码中,自动访问差异性的线程绑定的上下文相关信息

对TLS更简单的,但是更直观的理解可以如下(基于C语言):

1. 全局对象,全局变量的作用域和生命周期是全局的,这里的全局是指进程范畴,也就是说,如果你将其设计为全局对象,全局变量,就意味着你希望在多线程的环境中,仍然能共享和访问。 全局对象,全局变量不是说不让多线程来访问,而是说有的时候不期望他们同时访问,此时引入了线程的互斥,互斥的后果是保证不同时访问,但是,并没有改变共享的本质!

2. 如果设计的时候,就希望将某个对象,变量设计为线程局部的,那典型的是可以将其设计为函数的局部变量。 可是,我如果又希望在线程执行时,任意的函数和对象里面都可以访问到它那?! 此时,可能会想到用全局对象,全局变量,但是,它又会使得这种访问域上升到进程级别,其实,我只是想在线程局部环境中,全局访问该对象。
此时TLS应运而生,TLS就是达到了这种, 在线程局部环境(或者称呼为线程执行环境,线程上下文)下可以全局访问的对象/变量。

关于TLS的实际应用,更多的是定义一个TLS对象来存储一些线程上下文相关的信息。

给你取这样一个典型的例子吧,你可以看到TLS实际的应用场合。

在一个支持单进程,多线程的轻量级移动平台中,假设我实现了一个APP Framework,每一个APP单独运行在一个独立的线程中,APP运行时关联了很多信息,比如打开的文件,引用的组件,启动的Timer等等。我希望框架能实现自动垃圾回收,什么概念,就会应用退出的时候,即便应用没有主动释放打开的文件句柄,没有主动cancel
Timer,没有主动释放组件的引用,框架也可以自动完成这些收尾工作,否则,后果是不堪想象的。

好了,假设应用的退出是调用了框架的 ExitApp API, 该API允许应用调用后关闭自己,也允许关闭别的应用。 那么,假设该API触发了应用的退出,最终调用到框架的App_CleanUp函数,那么App_CleanUp函数除了完成应用本身实例的释放外,肯定是在这里来完成我们上面说的收尾工作,怎么来做哪?!
很明显,这里典型的,就可以使用TLS了。具体如下:

在Framework的API中,当应用的线程启动时,New 一个AppContext的对象或者结构体,然后将对象的指针或者结构体的指针以TLS的方式存储起来。 AppContext内部包含了文件句柄,timer引用,组件引用等等。 然后,后续任何框架的文件操作/Timer操作时,取当前线程的TLS,然后转换成AppContext后,将更新的文件句柄,timer引用等更新入AppContext对象内部。
然后,应用退出时,获取TLS,然后转换成AppContext,取出非空的文件句柄,组件引用,Timer引用等,来完成Cancel和Close操作。

其他不想说了,如果你能明白这个实际的例子,你就可以明白TLS的用途了。 上述的例子,来源于BREW/BMP框架内部的实际实现,当然有差别,但是思想是一样的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: