当前位置: 首页 > news >正文

网站建设与管理维护的答案李建青湖州十大进出口公司

网站建设与管理维护的答案李建青,湖州十大进出口公司,网络设计实验报告,网站换公司吗转载自 彻底理解ThreadLocal 先总述#xff0c;后分析 深挖过threadLocal之后#xff0c;一句话概括#xff1a;Synchronized用于线程间的数据共享#xff0c;而ThreadLocal则用于线程间的数据隔离。所以ThreadLocal的应用场合#xff0c;最适合的是按线程多实例#xff…转载自 彻底理解ThreadLocal 先总述后分析 深挖过threadLocal之后一句话概括Synchronized用于线程间的数据共享而ThreadLocal则用于线程间的数据隔离。所以ThreadLocal的应用场合最适合的是按线程多实例每个线程对应一个实例的对象的访问并且这个对象很多地方都要用到。 数据隔离的秘诀其实是这样的Thread有个TheadLocalMap类型的属性叫做threadLocals该属性用来保存该线程本地变量。这样每个线程都有自己的数据就做到了不同线程间数据的隔离保证了数据安全。 接下来采用jdk1.8源码进行深挖一下TheadLocal和TheadLocalMap。 ThreadLocal是什么 早在JDK 1.2的版本中就提供java.lang.ThreadLocalThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。 当使用ThreadLocal维护变量时ThreadLocal为每个使用该变量的线程提供独立的变量副本所以每一个线程都可以独立地改变自己的副本而不会影响其它线程所对应的副本。 从线程的角度看目标变量就象是线程的本地变量这也是类名中“Local”所要表达的意思。 所以在Java中编写线程局部变量的代码相对来说要笨拙一些因此造成线程局部变量没有在Java开发者中得到很好的普及。 原理 ThreadLocal连接ThreadLocalMap和Thread。来处理Thread的TheadLocalMap属性包括init初始化属性赋值、get对应的变量set设置变量等。通过当前线程获取线程上的ThreadLocalMap属性对数据进行get、set等操作。 ThreadLocalMap用来存储数据采用类似hashmap机制存储了以threadLocal为key需要隔离的数据为value的Entry键值对数组结构。 ThreadLocal有个ThreadLocalMap类型的属性存储的数据就放在这儿。 ThreadLocal、ThreadLocal、Thread之间的关系 ThreadLocalMap是ThreadLocal内部类由ThreadLocal创建Thread有ThreadLocal.ThreadLocalMap类型的属性。源码如下 Thread的属性 public class Thread implements Runnable { /*...其他属性...*/ /* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals null; /* * InheritableThreadLocal values pertaining to this thread. This map is * maintained by the InheritableThreadLocal class. */ ThreadLocal.ThreadLocalMap inheritableThreadLocals null; ThreadLocal和ThreadLocalMap public class ThreadLocalT { /**..其他属性和方法稍后介绍...*/ /** * ThreadLocalMap is a customized hash map suitable only for * maintaining thread local values. No operations are exported * outside of the ThreadLocal class. The class is package private to * allow declaration of fields in class Thread. To help deal with * very large and long-lived usages, the hash table entries use * WeakReferences for keys. However, since reference queues are not * used, stale entries are guaranteed to be removed only when * the table starts running out of space. */ static class ThreadLocalMap { 由ThreadLocal对Thread的TreadLocalMap进行赋值 /** * Create the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * param t the current thread * param firstValue value for the initial entry of the map */ void createMap(Thread t, T firstValue) { t.threadLocals new ThreadLocalMap(this, firstValue); } ThreadLocal的接口方法 ThreadLocal类核心方法set、get、initialValue、withInitial、setInitialValue、remove /** * Returns the current threads initial value for this * thread-local variable. This method will be invoked the first * time a thread accesses the variable with the {link #get} * method, unless the thread previously invoked the {link #set} * method, in which case the {code initialValue} method will not * be invoked for the thread. Normally, this method is invoked at * most once per thread, but it may be invoked again in case of * subsequent invocations of {link #remove} followed by {link #get}. * * pThis implementation simply returns {code null}; if the * programmer desires thread-local variables to have an initial * value other than {code null}, {code ThreadLocal} must be * subclassed, and this method overridden. Typically, an * anonymous inner class will be used. * * return the initial value for this thread-local */ protected T initialValue() { return null; } /** * Creates a thread local variable. The initial value of the variable is * determined by invoking the {code get} method on the {code Supplier}. * * param S the type of the thread locals value * param supplier the supplier to be used to determine the initial value * return a new thread local variable * throws NullPointerException if the specified supplier is null * since 1.8 */ public static S ThreadLocalS withInitial(Supplier? extends S supplier) { return new SuppliedThreadLocal(supplier); } /** * Creates a thread local variable. * see #withInitial(java.util.function.Supplier) */ public ThreadLocal() { } /** * Returns the value in the current threads copy of this * thread-local variable. If the variable has no value for the * current thread, it is first initialized to the value returned * by an invocation of the {link #initialValue} method. * * return the current threads value of this thread-local */ public T get() { Thread t Thread.currentThread(); ThreadLocalMap map getMap(t); if (map ! null) { ThreadLocalMap.Entry e map.getEntry(this); if (e ! null) { SuppressWarnings(unchecked) T result (T)e.value; return result; } } return setInitialValue(); } /** * Variant of set() to establish initialValue. Used instead * of set() in case user has overridden the set() method. * * return the initial value */ private T setInitialValue() { T value initialValue(); Thread t Thread.currentThread(); ThreadLocalMap map getMap(t); if (map ! null) map.set(this, value); else createMap(t, value); return value; } /** * Sets the current threads copy of this thread-local variable * to the specified value. Most subclasses will have no need to * override this method, relying solely on the {link #initialValue} * method to set the values of thread-locals. * * param value the value to be stored in the current threads copy of * this thread-local. */ public void set(T value) { Thread t Thread.currentThread(); ThreadLocalMap map getMap(t); if (map ! null) map.set(this, value); else createMap(t, value); } /** * Removes the current threads value for this thread-local * variable. If this thread-local variable is subsequently * {linkplain #get read} by the current thread, its value will be * reinitialized by invoking its {link #initialValue} method, * unless its value is {linkplain #set set} by the current thread * in the interim. This may result in multiple invocations of the * {code initialValue} method in the current thread. * * since 1.5 */ public void remove() { ThreadLocalMap m getMap(Thread.currentThread()); if (m ! null) m.remove(this); } initialValue返回该线程局部变量的初始值。该方法是一个protected的方法显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法在线程第1次调用get()或set(Object)时才执行并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。withInitial提供一个Supplier的lamda表达式用来当做初始值java8引入。setInitialValue设置初始值。在get操作没有对应的值时调用此方法。private方法防止被覆盖。过程和set类似只不过是用initialValue作为value进行设置。set设置当前线程对应的线程局部变量的值。先取出当前线程对应的threadLocalMap如果不存在则用创建一个否则将value放入以this即threadLocal为key的映射的map中其实threadLocalMap内部和hashMap机制一样存储了Entry键值对数组后续会深挖threadLocalMap。 get该方法返回当前线程所对应的线程局部变量。和set类似也是先取出当前线程对应的threadLocalMap如果不存在则用创建一个但是是用inittialValue作为value放入到map中且返回initialValue否则就直接从map取出this即threadLocal对应的value返回。 remove将当前线程局部变量的值删除目的是为了减少内存的占用该方法是JDK 5.0新增的方法。需要指出的是当线程结束后对应该线程的局部变量将自动被垃圾回收所以显式调用该方法清除线程的局部变量并不是必须的操作但它可以加快内存回收的速度。需要注意的是如果remove之后又调用了get会重新初始化一次即再次调用initialValue方法除非在get之前调用set设置过值。 ThreadLocalMap简介 看名字就知道是个map没错这就是个hashMap机制实现的map用Entry数组来存储键值对key是ThreadLocal对象value则是具体的值。值得一提的是为了方便GCEntry继承了WeakReference也就是弱引用。里面有一些具体关于如何清理过期的数据、扩容等机制思路基本和hashmap差不多有兴趣的可以自行阅读了解这边只需知道大概的数据存储结构即可。 /** * ThreadLocalMap is a customized hash map suitable only for * maintaining thread local values. No operations are exported * outside of the ThreadLocal class. The class is package private to * allow declaration of fields in class Thread. To help deal with * very large and long-lived usages, the hash table entries use * WeakReferences for keys. However, since reference queues are not * used, stale entries are guaranteed to be removed only when * the table starts running out of space. */ static class ThreadLocalMap { /** * The entries in this hash map extend WeakReference, using * its main ref field as the key (which is always a * ThreadLocal object). Note that null keys (i.e. entry.get() * null) mean that the key is no longer referenced, so the * entry can be expunged from table. Such entries are referred to * as stale entries in the code that follows. */ static class Entry extends WeakReferenceThreadLocal? { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal? k, Object v) { super(k); value v; } } Thread同步机制的比较 ThreadLocal和线程同步机制相比有什么优势呢 Synchronized用于线程间的数据共享而ThreadLocal则用于线程间的数据隔离。 在同步机制中通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的使用同步机制要求程序慎密地分析什么时候对变量进行读写什么时候需要锁定某个对象什么时候释放对象锁等繁杂的问题程序设计和编写难度相对较大。 而ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象在编写多线程代码时可以把不安全的变量封装进ThreadLocal。 概括起来说对于多线程资源共享的问题同步机制采用了“以时间换空间”的方式而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量让不同的线程排队访问而后者为每一个线程都提供了一份变量因此可以同时访问而互不影响。 Spring使用ThreadLocal解决线程安全问题我们知道在一般情况下只有无状态的Bean才可以在多线程环境下共享在Spring中绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等中非线程安全状态采用ThreadLocal进行处理让它们也成为线程安全的状态因为有状态的Bean就可以在多线程中共享了。 一般的Web应用划分为展现层、服务层和持久层三个层次在不同的层中编写对应的逻辑下层通过接口向上层开放功能调用。在一般情况下从接收请求到返回响应所经过的所有程序调用都同属于一个线程。 同一线程贯通三层这样你就可以根据需要将一些非线程安全的变量以ThreadLocal存放在同一次请求响应的调用线程中所有关联的对象引用到的都是同一个变量。 下面的实例能够体现Spring对有状态Bean的改造思路 代码清单3 TestDao非线程安全 package com.test; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; public class TestDao { private Connection conn;// ①一个非线程安全的变量 public void addTopic() throws SQLException { Statement stat conn.createStatement();// ②引用非线程安全变量 // … } } 由于①处的conn是成员变量因为addTopic()方法是非线程安全的必须在使用时创建一个新TopicDao实例非singleton。下面使用ThreadLocal对conn这个非线程安全的“状态”进行改造 代码清单4 TestDao线程安全 package com.test; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; public class TestDaoNew {// ①使用ThreadLocal保存Connection变量 private static ThreadLocalConnection connThreadLocal ThreadLocal.withInitial(Test::createConnection); // 具体创建数据库连接的方法 private static Connection createConnection() { Connection result null; /** * create a real connection... * such as : * result DriverManager.getConnection(dbUrl, dbUser, dbPwd); */ return result; } // ③直接返回线程本地变量 public static Connection getConnection() { return connThreadLocal.get(); } // 具体操作 public void addTopic() throws SQLException { // ④从ThreadLocal中获取线程对应的Connection Statement stat getConnection().createStatement(); //....any other operation } } 不同的线程在使用TopicDao时根据之前的深挖get具体操作判断connThreadLocal.get()会去判断是有map没有则根据initivalValue创建一个Connection对象并添加到本地线程变量中initivalValue对应的值也就是上述的lamba表达式对应的创建connection的方法返回的结果下次get则由于已经有了则会直接获取已经创建好的Connection这样就保证了不同的线程使用线程相关的Connection而不会使用其它线程的Connection。因此这个TopicDao就可以做到singleton共享了。 当然这个例子本身很粗糙将Connection的ThreadLocal直接放在DAO只能做到本DAO的多个方法共享Connection时不发生线程安全问题但无法和其它DAO共用同一个Connection要做到同一事务多DAO共享同一Connection必须在一个共同的外部类使用ThreadLocal保存Connection。 ConnectionManager.java package com.test; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class ConnectionManager { private static ThreadLocalConnection connectionHolder ThreadLocal.withInitial(() - { Connection conn null; try { conn DriverManager.getConnection( jdbc:mysql://localhost:3306/test, username, password); } catch (SQLException e) { e.printStackTrace(); } return conn; }); public static Connection getConnection() { return connectionHolder.get(); } } 线程隔离的秘密 秘密就就在于上述叙述的ThreadLocalMap这个类。ThreadLocalMap是ThreadLocal类的一个静态内部类它实现了键值对的设置和获取对比Map对象来理解每个线程中都有一个独立的ThreadLocalMap副本它所存储的值只能被当前线程读取和修改。ThreadLocal类通过操作每一个线程特有的ThreadLocalMap副本从而实现了变量访问在不同线程中的隔离。因为每个线程的变量都是自己特有的完全不会有并发错误。还有一点就是ThreadLocalMap存储的键值对中的键是this对象指向的ThreadLocal对象而值就是你所设置的对象了。 为了加深理解我们接着看上面代码中出现的getMap和createMap方法的实现 /** * Get the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * param t the current thread * return the map */ ThreadLocalMap getMap(Thread t) { return t.threadLocals; } /** * Create the map associated with a ThreadLocal. Overridden in * InheritableThreadLocal. * * param t the current thread * param firstValue value for the initial entry of the map * param map the map to store. */ void createMap(Thread t, T firstValue) { t.threadLocals new ThreadLocalMap(this, firstValue); } 小结 ThreadLocal是解决线程安全问题一个很好的思路它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。在很多情况下ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单更方便且结果程序拥有更高的并发性。 后记 看到网友评论的很激烈甚至关于ThreadLocalMap不是ThreadLocal里面的而是Thread里面的这种评论都出现了于是有了这个后记下面先把jdk源码贴上源码最有说服力了。 /** * ThreadLocalMap is a customized hash map suitable only for * maintaining thread local values. No operations are exported * outside of the ThreadLocal class. The class is package private to * allow declaration of fields in class Thread. To help deal with * very large and long-lived usages, the hash table entries use * WeakReferences for keys. However, since reference queues are not * used, stale entries are guaranteed to be removed only when * the table starts running out of space. */ static class ThreadLocalMap {...} 源码就是以上这源码自然是在ThreadLocal里面的有截图为证。 本文是自己在学习ThreadLocal的时候一时兴起深入看了源码思考了此类的作用、使用范围进而联想到对传统的synchronize共享变量线程安全的问题进行比较而总结的博文总结一句话就是一个是锁机制进行时间换空间一个是存储拷贝进行空间换时间。
http://www.huolong8.cn/news/18467/

相关文章:

  • 做网站从哪里找货源为什么做网站会被批捕
  • 文章类网站选什么内容嘉兴定制型网站建设
  • 做地方的门户网站网站主页模板图片
  • 做网站费用是什么微信公共平台官网
  • 洪梅做网站知识库管理系统软件
  • 网站开发工程师薪资待遇律师事务所网站建设策划方案
  • 网页设计与网站建设考试名词解释河间网站网站建设
  • 诸城网站建设多少钱大连公司名称大全
  • 培训网站开发哪个好兰州网络推广哪家好
  • 网站导航页面模板seo策略
  • 北京网站制作案例施工企业会计分录大全
  • 构建网站无障碍建设北京土巴兔全包装修价格表
  • 中信建设有限责任公司内部网站图书网站怎么做
  • 网站如何做服务器授权书成都网站建设:思乐科技
  • 从零开始学网站建设建设厅网站合同备案在哪里
  • 制作钓鱼网站的费用重庆品牌餐饮加盟网站建设
  • wordpress里网站名称在哪里修改西夏区建设交通网站
  • 如何对网站做优化南桥做网站
  • 如何做淘宝的站外网站推广东莞企业为什么网站建设
  • 网站建设与网络编辑心得体会互联网技术的特征
  • 做视频网站用什么服务器配置手机wordpress主题
  • ps做的图怎么做成网站前端东莞大型企业
  • 骨干校建设专题网站网站流量 钱
  • 网站建设服务器维护内容2021年企业所得税优惠政策最新
  • 衡水网站设计怎么做东莞城市规划局
  • 网站制作加教程视频教程wordpress苏醒主题grace
  • 利用js做简单的网站wordpress登录后搜索
  • 合肥专业做淘宝网站建设wordpress 链接无效
  • 成都设计网站的公司名称河南新乡市建设银行网站
  • 站酷官网入口php 信息分类网站开发