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

被墙域名黑别人网站电子商务网站建设的实训报告

被墙域名黑别人网站,电子商务网站建设的实训报告,可以不进网站开发app吗,视频拍摄技巧前言 ThreadLocal想必都不陌生#xff0c;当多线程访问同一个共享变量时#xff0c;就容易出现并发问题#xff0c;为了保证线程安全#xff0c;我们需要对共享变量进行同步加锁#xff0c;但这又带来了性能消耗以及使用者的负担#xff0c;那么有没有可能当我们创建一个…前言 ThreadLocal想必都不陌生当多线程访问同一个共享变量时就容易出现并发问题为了保证线程安全我们需要对共享变量进行同步加锁但这又带来了性能消耗以及使用者的负担那么有没有可能当我们创建一个共享变量时每个线程对其访问的时候访问的都是自己线程的变量呢没错那就是ThreadLocal。 ThreadLocal使用 举个简单例子 比如实现一些数据运算的操作过程中可能需要借助一个临时表去处理数据临时表有一列存的每一次的执行ID执行完成根据此次的执行ID进行删除临时表数据。可以使用一个ThreadLocal来存储当前线程的执行ID。 public class DataSyncServiceImpl {private final Logger logger LoggerFactory.getLogger(DataSyncServiceImpl.class);private static final ThreadLocalString execLocalId ThreadLocal.withInitial(()-new String());Autowiredprivate JdbcTemplate jdbcTemplate;/*** 借助临时表进行数据运算操作* 临时表字段idexecution_id*/public void calculateData(String key){try {execLocalId.set(UUID.randomUUID().toString());calculate();check();System.out.println(同步数据...);}finally {destory();}}private void calculate(){try {System.out.println(数据运算);String execId execLocalId.get();//...Thread.sleep(1000L);} catch (InterruptedException e) {logger.error(执行异常,e);}}private void check(){try {System.out.println(数据运算);String execId execLocalId.get();//...Thread.sleep(1000L);} catch (InterruptedException e) {logger.error(执行异常,e);}}private void destory(){//根据execution_id删除临时表数据StringBuffer sql new StringBuffer();sql.append(delete from temp_table where execution_id ?);jdbcTemplate.update(sql.toString(),execLocalId.get());execLocalId.remove();} }这样的话保证了每一个请求线程都有自己的执行ID清除数据时互不影响。 ThreadLocal实现原理 进入Thread类可以看到这样两个变量threadLocals和inheritableThreadLocals他们都是ThreadLocalMap类型而ThreadLocalMap是一个类似Map的结构。默认情况下两个变量都为null当前线程调用set或者get时才会创建。也就是说ThreadLocal变量其实是存在调用线程的内存空间中。每个Thread线程都保存了一个共享变量的副本。 1、threadLocals当前线程的ThreadLocal变量 2、inheritableThreadLocals解决子线程不能访问父线程中的ThreadLocal变量 ThreadLocalMap ThreadLocalMap是一个key为ThreadLocal本身值为存入的value对于不同的线程每次获取副本时别的线程不能获取到当前线程的副本值形成了隔离。 Thread和ThreadLocal的关系 Set方法源码分析 * 设置当前线程对应的ThreadLocal的值* param value 将要保存在当前线程对应的ThreadLocal的值*/public void set(T value) {// 获取当前线程对象Thread t Thread.currentThread();// 获取此线程对象中维护的ThreadLocalMap对象ThreadLocalMap map getMap(t);// 判断map是否存在if (map ! null)// 存在则调用map.set设置此实体entry,this这里指调用此方法的ThreadLocal对象map.set(this, value);else// 1当前线程Thread 不存在ThreadLocalMap对象// 2则调用createMap进行ThreadLocalMap对象的初始化// 3并将 t(当前线程)和value(t对应的值)作为第一个entry存放至ThreadLocalMap中createMap(t, value);}/*** 获取当前线程Thread对应维护的ThreadLocalMap * * param t the current thread 当前线程* return the map 对应维护的ThreadLocalMap */ThreadLocalMap getMap(Thread t) {return t.threadLocals;}/***创建当前线程Thread对应维护的ThreadLocalMap * param t 当前线程* param firstValue 存放到map中第一个entry的值*/void createMap(Thread t, T firstValue) {//这里的this是调用此方法的threadLocalt.threadLocals new ThreadLocalMap(this, firstValue);}执行步骤 获取当前线程根据当前线程获取到ThreadlocalMap即threadLocals 如果获取到的Map不为空则设置valuekey为调用此方法的ThreadLocal引用 如果Map为空则先调用createMap创建再设置value。 Get方法源码分析 * 返回当前线程中保存ThreadLocal的值* 如果当前线程没有此ThreadLocal变量* 则它会通过调用{link #initialValue} 方法进行初始化值* return 返回当前线程对应此ThreadLocal的值*/public T get() {// 获取当前线程对象Thread t Thread.currentThread();// 获取此线程对象中维护的ThreadLocalMap对象ThreadLocalMap map getMap(t);// 如果此map存在if (map ! null) {// 以当前的ThreadLocal 为 key调用getEntry获取对应的存储实体eThreadLocalMap.Entry e map.getEntry(this);// 对e进行判空 if (e ! null) {SuppressWarnings(unchecked)// 获取存储实体 e 对应的 value值,即为我们想要的当前线程对应此ThreadLocal的值T result (T)e.value;return result;}}/*初始化 : 有两种情况有执行当前代码第一种情况: map不存在表示此线程没有维护的ThreadLocalMap对象第二种情况: map存在, 但是没有与当前ThreadLocal关联的entry*/return setInitialValue();}/*** 初始化* return the initial value 初始化后的值*/private T setInitialValue() {// 调用initialValue获取初始化的值// 此方法可以被子类重写, 如果不重写默认返回nullT value initialValue();// 获取当前线程对象Thread t Thread.currentThread();// 获取此线程对象中维护的ThreadLocalMap对象ThreadLocalMap map getMap(t);// 判断map是否存在if (map ! null)// 存在则调用map.set设置此实体entrymap.set(this, value);else// 1当前线程Thread 不存在ThreadLocalMap对象// 2则调用createMap进行ThreadLocalMap对象的初始化// 3并将 t(当前线程)和value(t对应的值)作为第一个entry存放至ThreadLocalMap中createMap(t, value);// 返回设置的值valuereturn value;}执行步骤 1、获取当前线程获取此线程对象中维护的ThreadLocalMap对象 2、如果Map不为空则通过当前调用的ThreadLocal对象获取Entry; 3、判断Entry不为空则直接返回value 4、Map或Entry为空则通过initialValue函数获取初始值value然后用ThreadLocal的引用和value作为Key和Value创建一个新的Map。 内存泄漏 从ThreadLocal整体设计上我们可以看到key持有ThreadLocal的弱引用GC的时候会被回收即Entry的key为null。但是当我们没有手动删除这个Entry或者线程一直运行的前提下存在有强引用链 threadRef-currentThread-threadLocalMap-entry - value value不会被回收导致内存泄漏。 出现内存泄漏的情况 1、没有手动删除对应的Entry节点信息value一直存在。 2、ThreadLocal 对象使用完后对应线程仍然在运行。 避免内存泄露 1、使用完ThreadLocal调用其remove方法删除对应的Entry。 2、对于第二种情况因为使用了弱引用当ThreadLocal 使用完后key的引用就会为null而在调用ThreadLocal 中的get()/set()方法时当判断key为null时会将value置为null这就就会在jvm下次GC时将对应的Entry对象回收从而避免内存泄漏问题的出现。 总结 本文主要讲解了ThreadLocal的作用及基本用法以及ThreadLocal的实现原理和基础方法注意事项。最后用ThreadLocal一定要记得用完remove
http://www.w-s-a.com/news/133/

相关文章:

  • 免费快速网站十八个免费的舆情网站