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

网站优化联系邯郸网站制作地方

网站优化联系,邯郸网站制作地方,网站到期了,网站配色方法JMM Java内存模型规定所有的变量都存储在主内存中#xff0c;包括实例变量#xff0c;静态变量#xff0c;但是不包括局部变量和方法参数。每个线程都有自己的工作内存#xff0c;线程的工作内存保存了该线程用到的变量和主内存的副本拷贝#xff0c;线程对变量的操作都在…JMM Java内存模型规定所有的变量都存储在主内存中包括实例变量静态变量但是不包括局部变量和方法参数。每个线程都有自己的工作内存线程的工作内存保存了该线程用到的变量和主内存的副本拷贝线程对变量的操作都在工作内存中进行。线程不能直接读写主内存中的变量。 工作内存和主内存 Java内存模型规定所有变量都存储在主内存中线程不能对主内存直接进行操作只能加载到工作内存中这样就会造成不可见性. lock(锁定)作用于主内存中的变量把变量标识为线程独占的状态。 read(读取)作用于主内存的变量把变量的值从主内存传输到线程的工作内存中以便下一步的load操作使用。 load(加载)作用于工作内存的变量把read操作主存的变量放入到工作内存的变量副本中。 use(使用)作用于工作内存的变量把工作内存中的变量传输到执行引擎每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作。 assign(赋值)作用于工作内存的变量它把一个从执行引擎中接受到的值赋值给工作内存的变量副本中每当虚拟机遇到一个给变量赋值的字节码指令时将会执行这个操作。 store(存储)作用于工作内存的变量它把一个从工作内存中一个变量的值传送到主内存中以便后续的write使用。 write(写入)作用于主内存中的变量它把store操作从工作内存中得到的变量的值放入主内存的变量中。 unlock(解锁)作用于主内存的变量它把一个处于锁定状态的变量释放出来释放后的变量才可以被其他线程锁定。 不可见性 一个线程对共享变量进行修改时另一个线程不能够立刻看到每个 CPU 内核都有自己的缓存而缓存仅仅对它所在的处理器内核可见CPU 缓存与内存的数据不容易保证一致。 乱序性 为了优化代码将指令顺序改变这样的操作会影响到运行结果 内存屏障 内存屏障是硬件层的概念不同的硬件平台实现内存屏障的手段并不是一样java通过屏蔽这些差异统一由jvm来生成内存屏障的指令在每个volatile写操作前插入StoreStore屏障在写操作后插入StoreLoad屏障在每个volatile读操作前插入LoadLoad屏障在读操作后插入LoadStore屏障由于内存屏障的作用避免了volatile变量和其它指令重排序、实现了线程之间通信使得volatile表现出了锁的特性。 非原子性 进程切换带来了非原子性问题 如何解决 加锁 使用synchronized在a线程执行时加锁其他线程就不能执行 public synchronized void increase() {counter;   } 原子变量 在java.util.concurrent 包下面提供一些类,可以在不加锁的情况下实现操作的原子性. 这些类称为原子类 AtomicInteger. private AtomicInteger counter new AtomicInteger(0);public void increase() {counter.getAndIncrement(); } ​ unsafe // val1: AtomicInteger对象本身var2: 该对象值得引用地址var4: 需要变动的数 public final int getAndSetInt(Object var1, long var2, int var4) {int var5;do {// var5: 用 var1 和 var2 找到的内存中的真实值var5 this.getIntVolatile(var1, var2);} while(!this.compareAndSwapInt(var1, var2, var5, var4)); ​return var5; } var5从主内存中拷贝到工作内存中的值每次都要从主内存拿到最新的值到本地内存然后执行 compareAndSwapInt() 再和主内存的值进行比较假设方法返回 false那么就一直执行 while 方法直到期望的值和真实值一样修改数据 CAS机制 CAS 是乐观锁的一种实现他采用的是自旋的思想是一种轻量级的锁机制。即每次判断我的预期值和内存中的值是不是相同如果不相同则说明该内存值已经被其他线程更新过了因此需要拿到该最新值作为预期值重新判断。而该线程不断的循环判断是否该内存值已经被其他线程更新过了这就是自旋的思想。底层是通过 Unsafe 类中的 compareAndSwapInt 等方法实现.CAS是一条CPU的原子指令cmpxchg指令不会造成数据不一致问题 缺点 采用了自旋锁方式不断循环会导致cpu的消耗 造成ABA问题 这个问题通常发生在使用CAS操作的并发环境中,我们可以使用版本号的方式来解决这个问题,每次变量更新的时候版本号加1,那么A-B-A这个过程就会被检测出来。AtomicStampedReference就是用过这个原理来解决ABA问题的,它包含一个值和一个版本号,我们可以这样使用: AtomicStampedReferenceInteger atomicRef new AtomicStampedReference(100, 0);// 获取当前值和版本号   int stamp atomicRef.getStamp(); int value atomicRef.getReference();// 尝试设置新值和版本号 boolean success atomicRef.compareAndSet(value, 101, stamp, stamp 1); if(success) {// 设置成功,获取新版本号stamp atomicRef.getStamp(); }   解决方法 使用版本号1A2B3AJUC包中提供了AtomicStampedReference来解决compareAndSet方法会检查版本号和以用只有全部相同时才会返回True Atomic AtomicInteger 原理自旋锁 CAS 算法 CAS 算法有 3 个操作数内存值 V 旧的预期值 A要修改的值 B 当旧的预期值 A 内存值 V 此时可以修改将 V 改为 B 当旧的预期值 A ! 内存值 V 此时不能修改并重新获取现在的最新值重新获取的动作就是自旋 volatile 是Java虚拟机提供那个的轻量级的同步机制一旦一个共享变量被volatile修饰后就具备了两层语义 1保证了不同线程对这个变量进行操作时的可见性即一个线程修改了某个变量的值这新值对其他线程来说是立即可见的。 2禁止进行指令重排序 底层实现 内存屏障 强制让读写都访问主内存读写操作时都会加入屏障 缓存一致性 某个处理器更新了共享变量之后缓存一致性协议就会保证其他的处理器也能看到修改后的值缓存一致性原则会在读操作前写操作后都会刷新内存保证访问的数据都是最新的 总结 volatile关键字主要保证可见性、有序性和禁止编译器优化。 volatile的底层原理是依赖内存屏障和缓存一致性协议实现的。 volatile不能保证原子性,要配合synchronized或Atomic类解决。 volatile的实现依赖JMM中的主内存、工作内存和内存屏障等概念。 锁分类 乐观锁和悲观锁 乐观锁与悲观锁不是指具体的什么类型的锁而是指看待并发同步的角度 乐观锁 认为在对同一个数据的并发操作时是不会发生修改的其实就是不加锁在更新数据的时候会采用尝试更新不断重新的方式更新数据。CAS的实现思想就是乐观锁 悲观锁 与乐观锁相反认为对于同一个数据的并发操作一定是会发生修改的哪怕没有修改也会认为修改。适用于写多读少的操作当一个线程获得锁对象时其他线程只能在外等待直到第一个线程释放锁为止 可重入锁和不可重入锁 可重入锁 又名递归锁在持有一个锁对象时还可以对另一个同步方法进行操作synchronized和ReentrantLock都是可重入锁在一定程度上可以避免死锁的发生 public class AB{// 演示可重入锁synchronized void setA() throws Exception{   Thread.sleep(1000);setB();   // 因为获取了setA()的锁即获取了方法外层的锁、此时调用setB()将会自动获取setB()的锁如果不自动获取的话方法B将不会执行           }synchronized void setB() throws Exception{Thread.sleep(1000);} } 不可重入锁 线程对象的同步方法上锁后其他的同步方法需要排队等候递归调用时会发生死锁 公平锁和非公平锁 公平锁 线程进入进行等待队首的元素会获得锁对象按照获得锁对象的顺序执行代码 优点不会造成线程饿死的现象 缺点除了第一个线程其余线程会造成阻塞现象 非公平锁synchronized 不按照请求锁的顺序分配,谁抢到谁获得 对于Synchronized而言是一种非公平锁。并不像ReentrantLock是通过AQS的来实现线程调度所以synchronized并没有任何办法使其变成公平锁。 共享锁和独占锁 共享锁 并发包中ReadWriteLock就是一个典型的共享锁。它允许一个资源可以被多个读操作访问或者被一个 写操作访问但两者不能同时进行。 独占锁 该锁一次只能被一个线程所持有而其他线程就只能等待当前持有锁的线程释放锁才能再次获取锁Synchronized、ReentrantLock都是独享锁其实准确的说独占锁也是悲观锁因为悲观锁也是其他线程只能等待持有锁的线程释放锁才能再次获取到锁资源。 读写锁 读读不互斥读写和写写之间互斥防止其他线程在此时写入数据造成数据的脏读 分段锁 在jdk8之后去除了真正的分段锁此处的分段锁只是一种思想将锁的粒度更细化例如concurrentHashMap中用hash表中的第一个结点当作锁 自旋锁 即当一个线程在获取锁的时候如果锁已经被其它线程获取那么该线程将循环等待然后不断的判断锁是否能够被成功获取直到获取到锁才会退出循环。尝试获取锁的线程不会立即阻塞(放弃CPU时间片)采用循环的方式尝试获取锁 对象结构 在 Hotspot 虚拟机中对象在内存中的布局分为三块区域对象头、实例数据和对齐填充Java 对象头是实现 synchronized 的锁对象的基础一般而言synchronized 使用的锁对象是存储在 Java 对象头里。它是轻量级锁和偏向锁的关键 对象头中有一块区域称为 Mark Word,用于存储对象自身的运行时数据如哈希码HashCode、GC 分代年龄、锁状态标志、线程持有的锁、偏向线程 ID等等 Synchronized实现 synchronized作用在静态方法时锁的是对象的Class实例因为Class数据存在于元空间JDK8前是永久代因此静态方法锁相当于该类的一个全局锁 当synchronized作用在某一个对象实例时锁的是括号括起来的对象实例(XXX) synchronized通过底层指令实现控制 修饰方法时 底层指令添加ACC_SYNCHRONIZED 进入方法时使用monitorenter检测 执行完毕使用monitorexit释放锁 修饰代码块时 进入方法时使用monitorenter检测 执行完毕使用monitorexit释放锁 无锁/偏向锁/轻量级锁/重量级锁 在synchronized包裹起来的代码被称为同步块在使用过程中锁的状态会发生一系列升级主要有四个方面 无锁 没有任何线程使用锁对象 偏向锁 一段代码一直被同一个线程访问首先读取目标对象的MarkWord判断是否为可偏向状态 如果为可偏向状态, 则尝试用 CAS 操作 将自己的线程 ID 写入MarkWord 如果 CAS 操作失败 则说明 有另外一个线程 Thread B 抢先获取了偏向锁。 这种状态说明该对象的竞争比较激烈 此时需要撤销 Thread B 获得的偏向锁将 Thread B 持有的锁升级为轻量级锁。 如果是已偏向状态 则检测 MarkWord 中存储的 thread ID 是否等于当前 thread ID 。 如果相等 则证明本线程已经获取到偏向锁 可以直接继续执行同步代码块 如果不等 则证明该对象目前偏向于其他线程 需要撤销偏向锁 轻量级锁 当前锁的状态为偏向锁时此时继续有线程去访问一个代码线程尝试使用 CAS 操作将对象头中的 Mark Word 替换为指向锁记录的指针如果CAS操作成功如果成功当前线程获得锁 重量级锁 当锁的状态为轻量级锁时,线程自旋获取锁的次数到达一定数量时,锁的状态升级为重量级锁,会让自旋次数多的线程进入到阻塞状态,因为访问大时,线程都自旋获得锁,cpu消耗大. AQS AbstractQueuedSynchronizer意为抽象同步队列内部由32 bit int来维护同步状态独占模式0表示未加锁大于0表示加锁状态如果被请求的共享资源空闲则将当前请求资源的线程设置为有效的工作线程并将共享资源设置锁定状态 state 使用 volatile 修饰配合 cas 保证其修改时的原子性 CLH 是一种基于单向链表的高性能、公平的自旋锁AQS 是将每条请求共享资源的线程封装成一个 CLH 锁队列的一个结点Node来实现锁的分配 ReentrantLock实现 锁对比 ReentrantLock 相对于 synchronized 具备如下特点 锁的实现synchronized 是 JVM 实现的而 ReentrantLock 是 JDK 实现的 性能新版本 Java 对 synchronized 进行了很多优化synchronized 与 ReentrantLock 大致相同 使用ReentrantLock 需要手动解锁synchronized 执行完代码块自动解锁 可中断ReentrantLock 可中断而 synchronized 不行 公平锁公平锁是指多个线程在等待同一个锁时必须按照申请锁的时间顺序来依次获得锁 ReentrantLock 可以设置公平锁synchronized 中的锁是非公平的 不公平锁的含义是阻塞队列内公平队列外非公平 锁超时尝试获取锁超时获取不到直接放弃不进入阻塞队列 ReentrantLock 可以设置超时时间synchronized 会一直等待 锁绑定多个条件一个 ReentrantLock 可以同时绑定多个 Condition 对象更细粒度的唤醒线程 两者都是可重入锁 使用锁 构造方法ReentrantLock lock new ReentrantLock(); ReentrantLock 类 API public void lock()获得锁 如果锁没有被另一个线程占用则将锁定计数设置为 1 如果当前线程已经保持锁定则保持计数增加 1 如果锁被另一个线程保持则当前线程被禁用线程调度并且在锁定已被获取之前处于休眠状态 public void unlock()尝试释放锁 如果当前线程是该锁的持有者则保持计数递减 如果保持计数现在为零则锁定被释放 如果当前线程不是该锁的持有者则抛出异常 公平锁 基本使用 构造方法ReentrantLock lock new ReentrantLock(true) public ReentrantLock(boolean fair) {sync fair ? new FairSync() : new NonfairSync(); } ReentrantLock 默认是不公平的 public ReentrantLock() {sync new NonfairSync(); } 说明公平锁一般没有必要会降低并发度 非公平锁 static final class NonfairSync extends Sync {//实现加锁 final void lock() {if (compareAndSetState(0, 1)) //先尝试获取锁,修改锁的状态setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}}// ReentrantLock.NonfairSync#tryAcquire protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires); } // 抢占成功返回 true抢占失败返回 false final boolean nonfairTryAcquire(int acquires) {final Thread current Thread.currentThread();// state 值int c getState();// 条件成立说明当前处于【无锁状态】if (c 0) {//如果还没有获得锁尝试用cas获得这里体现非公平性: 不去检查 AQS 队列是否有阻塞线程直接获取锁        if (compareAndSetState(0, acquires)) {// 获取锁成功设置当前线程为独占锁线程。setExclusiveOwnerThread(current);return true;}    }    // 如果已经有线程获得了锁, 独占锁线程还是当前线程, 表示【发生了锁重入】else if (current getExclusiveOwnerThread()) {// 更新锁重入的值int nextc c acquires;// 越界判断当重入的深度很深时会导致 nextc 0int值达到最大之后再 1 变负数if (nextc 0) // overflowthrow new Error(Maximum lock count exceeded);// 更新 state 的值这里不使用 cas 是因为当前线程正在持有锁所以这里的操作相当于在一个管程内setState(nextc);return true;}// 获取失败return false; } JUC常用类 ConcurrentHashMap 三种集合 HashMap 是线程不安全的性能好 Hashtable 线程安全基于 synchronized综合性能差已经被淘汰 ConcurrentHashMap 保证了线程安全综合性能较好不止线程安全而且效率高性能好 虽然HashTable是线程安全的但是只是单纯在put()方法上加锁保证插入操作时阻塞其他线程的操作效率低下ConcurrentHashMap采用了cassynchronized保证了多线程的线程安全,他的键值都不能为空也包括HashTable防止出现歧义 源码 //ConcurrentHashMap使用volatile修饰节点数组保证其可见性禁止指令重排。 transient volatile NodeK,V[] table; final V putVal(K key, V value, boolean onlyIfAbsent) {// 【ConcurrentHashMap 不能存放 null 值】if (key null || value null) throw new NullPointerException();// 扰动运算高低位都参与寻址运算int hash spread(key.hashCode());// 表示当前 k-v 封装成 node 后插入到指定桶位后在桶位中的所属链表的下标位置int binCount 0;// tab 引用当前 map 的数组 table开始自旋for (NodeK,V[] tab table;;) {// f 表示桶位的头节点n 表示哈希表数组的长度// i 表示 key 通过寻址计算后得到的桶位下标fh 表示桶位头结点的 hash 值NodeK,V f; int n, i, fh;// 【CASE1】表示当前 map 中的 table 尚未初始化if (tab null || (n tab.length) 0)//【延迟初始化】tab initTable();// 【CASE2】i 表示 key 使用【寻址算法】得到 key 对应数组的下标位置tabAt 获取指定桶位的头结点felse if ((f tabAt(tab, i (n - 1) hash)) null) {// 对应的数组为 null 说明没有哈希冲突直接新建节点添加到表中if (casTabAt(tab, i, null, new NodeK,V(hash, key, value, null)))break;}// 【CASE3】逻辑说明数组已经被初始化并且当前 key 对应的位置不为 null// 条件成立表示当前桶位的头结点为 FWD 结点表示目前 map 正处于扩容过程中else if ((fh f.hash) MOVED)// 当前线程【需要去帮助哈希表完成扩容】tab helpTransfer(tab, f);// 【CASE4】哈希表没有在扩容当前桶位可能是链表也可能是红黑树else {// 当插入 key 存在时会将旧值赋值给 oldVal 返回V oldVal null;// 【锁住当前 key 寻址的桶位的头节点】synchronized (f) {// 这里重新获取一下桶的头节点有没有被修改因为可能被其他线程修改过这里是线程安全的获取if (tabAt(tab, i) f) {// 【头节点的哈希值大于 0 说明当前桶位是普通的链表节点】if (fh 0) {// 当前的插入操作没出现重复的 key追加到链表的末尾binCount表示链表长度 -1// 插入的key与链表中的某个元素的 key 一致变成替换操作binCount 表示第几个节点冲突binCount 1;// 迭代循环当前桶位的链表e 是每次循环处理节点e 初始是头节点for (NodeK,V e f;; binCount) {// 当前循环节点 keyK ek;// key 的哈希值与当前节点的哈希一致并且 key 的值也相同if (e.hash hash ((ek e.key) key ||(ek ! null key.equals(ek)))) {// 把当前节点的 value 赋值给 oldValoldVal e.val;// 允许覆盖if (!onlyIfAbsent)// 新数据覆盖旧数据e.val value;// 跳出循环break;}NodeK,V pred e;// 如果下一个节点为空把数据封装成节点插入链表尾部【binCount 代表长度 - 1】if ((e e.next) null) {pred.next new NodeK,V(hash, key,value, null);break;}}}// 当前桶位头节点是红黑树else if (f instanceof TreeBin) {NodeK,V p;binCount 2;if ((p ((TreeBinK,V)f).putTreeVal(hash, key,value)) ! null) {oldVal p.val;if (!onlyIfAbsent)p.val value;}}}}// 条件成立说明当前是链表或者红黑树if (binCount ! 0) {// 如果 binCount 8 表示处理的桶位一定是链表说明长度是 9if (binCount TREEIFY_THRESHOLD)// 树化treeifyBin(tab, i);if (oldVal ! null)return oldVal;break;}}}// 统计当前 table 一共有多少数据判断是否达到扩容阈值标准触发扩容// binCount 0 表示当前桶位为 nullnode 可以直接放入2 表示当前桶位已经是红黑树addCount(1L, binCount);return null; } 扰动函数:将 hashCode 无符号右移 16 位高 16bit 和低 16bit 做异或最后与 HASH_BITS 相与变成正数与树化节点和转移节点区分把高低位都利用起来减少哈希冲突保证散列的均匀性 static final int spread(int h) {return (h ^ (h 16)) HASH_BITS; // 0111 1111 1111 1111 1111 1111 1111 1111 } CopyOnWriteArrayList CopyOnWriteArrayList 采用了写入时拷贝的思想增删改操作会将底层数组拷贝一份在新数组上执行操作不影响其它线程的并发读读写分离 存储结构 private transient volatile Object[] array; // volatile 保证了读写线程之间的可见性 全局锁 final transient ReentrantLock lock new ReentrantLock(); CopyOnWriteArraySet CopyOnWriteArraySet 的实现基于 CopyOnWriteArrayList,不能存储重复数据 CountDownLatch CountDownLatch计数器用来进行线程同步协作等待所有线程完成,允许一个线程等待其他线程执行完成后再执行内部采用AQS每次state-1当减到0时闭锁线程才会执行 public class CountDownLatchDemo { ​public static void main(String[] args) throws InterruptedException { ​ ​/*允许一个线程等待其他线程执行完毕后,在执行*/CountDownLatch countDownLatch new CountDownLatch(10);//设置线程总量 ​for (int i 0; i 10 ; i) {new Thread(()-{try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(aaaaaaaaaaaaa);countDownLatch.countDown();}).start();}countDownLatch.await(); ​System.out.println(main线程执行);//最后执行的内容 ​} } 线程池 基本概述 线程池一个容纳多个线程的容器容器中的线程可以重复使用省去了频繁创建和销毁线程对象的操作 线程池作用 降低资源消耗减少了创建和销毁线程的次数每个工作线程都可以被重复利用可执行多个任务 提高响应速度当任务到达时如果有线程可以直接用不会出现系统僵死 提高线程的可管理性如果无限制的创建线程不仅会消耗系统资源还会降低系统的稳定性使用线程池可以进行统一的分配调优和监控 线程池的核心思想线程复用同一个线程可以被重复使用来处理多个任务 池化技术 (Pool) 一种编程技巧核心思想是资源复用在请求量大时能优化应用性能降低系统频繁建连的资源开销 ThreadPoolExecutor 在 JDK5 版本中增加了内置线程池实现 ThreadPoolExecutor同时提供了Executors 来创建不同类型的线程池。Executors 中提供了以下常见的线程池创建方法 newSingleThreadExecutor一个单线程的线程池。如果因异常结束会再创建一个新的保证按照提交顺序执行。 newFixedThreadPool创建固定大小的线程池。根据提交的任务逐个增加线程直到最大值保持不变。如果因异常结束会新创建一个线程补充。 newCachedThreadPool创建一个可缓存的线程池。会根据任务自动新增或回收线程 虽然在 JDK 中提供 Executors 类来支持以上类型的线程池创建但通常情况下不建议开发人员直接使用见《阿里巴巴 java 开发规范》并发处理 七个参数 corePoolSize核心池数量 maximumPoolSize最大线程数 keepAliveTime除去核心线程外如果一个线程的空闲时间大于keepAliveTime将会被销毁 unit时间参数 workQueue阻塞队列 threadFactory线程工厂主要用于创建线程 handler拒绝策略 执行流程 线程池队列 ArrayBlockingQueue是一个用数组实现的有界阻塞队列,创建时必须设置长度,按 FIFO 排序量。 LinkedBlockingQueue基于链表结构的阻塞队列按 FIFO 排序任务容量可以选择进行设置不设置是一个最大长度为 Integer.MAX_VALUE 拒绝策略 AbortPolicy抛出异常 CallerRunsPolicy由提交任务的线程执行main线程 DiscardOlddestPolicy丢弃最老的一个线程 DiscardPolicy直接丢弃之后的请求 execute 与 submit 的区别 excute 实现Runnable接口没有返回值 submit 实现Runnable接口和Callable接口有返回值 关闭线程池 shutdown 不会接收新的任务等待所有的线程执行完毕后再关闭 shutdownNow 对正在执行的任务全部发出 interrupt()停止执行对还未开始执行的任务全部取消并且返回还没开始的任务列表。 ThreadLocal 意为本地线程变量,意思是 ThreadLocal 中填充的变量属于当前线程该变量对其他线程而言是隔离的。ThreadLocal 为变量在每个线程中都创建了一个副本那么每个线程可以访问自己内部的副本变量 static ThreadLocalInteger threadLocal new ThreadLocalInteger(){Overrideprotected Integer initialValue() {return 1;} }; public void set(T value) {// 获取当前的Thread线程Thread t Thread.currentThread();// 获取当前线程的ThreadLocalMapThreadLocalMap map getMap(t);if (map ! null)// 将当前ThreadLocal作为key保存到ThreadLocalMap中map.set(this, value);else// 初始化ThreadLocalMapcreateMap(t, value); } ​ public T get() {// 获取当前线程Thread t Thread.currentThread();// 获取当前线程的ThreadLocalMapThreadLocalMap map getMap(t);if (map ! null) {// 利用当前ThreadLocal作为key获取valueThreadLocalMap.Entry e map.getEntry(this);if (e ! null) {SuppressWarnings(unchecked)T result (T)e.value;return result;}}// 初始化ThreadLocalMap或者直接通过ThreadLocalMap设置valuereturn setInitialValue(); } ​ public void remove() {// 获取当前线程的ThreadLocalMapThreadLocalMap m getMap(Thread.currentThread());if (m ! null)// 移除当前ThreadLocalMap中的ThreadLocal对象m.remove(this);} ​ 内存泄漏 TreadLocalMap 使用 ThreadLocal 的弱引用作为 key如果一个 ThreadLocal不存在外部强引用时Key(ThreadLocal)势必会被 GC 回收这样就会导致ThreadLocalMap 中 key 为 null 而 value 还存在着强引用只有 thead 线程退出以后,value 的强引用链条才会断掉。
http://www.zqtcl.cn/news/738188/

相关文章:

  • 新建的网站怎么做seo优化平面广告创意设计
  • yy陪玩网站怎么做软件项目管理计划
  • 西安建网站价格低百度推广区域代理
  • 中英网站模板 照明公司注册在自贸区的利弊
  • 全球十大网站排名wordpress标题连接符
  • 网站开发可能遇到的问题四川建筑人才招聘网
  • 镇江网站托管怎么做淘宝网站赚钱吗
  • 交互式网站是什么知名vi设计企业
  • 上海个人做网站网站建设销售好做嘛
  • 邵阳建设网站哪家好手机网站栏目结构图
  • 做动车哪个网站查网站环境配置
  • 那些网站可以做h5国内新闻最新消息今天简短
  • asp网站开发实例河南省建设招投标网站
  • 营销型网站搭建公司有没有专做推广小说的网站
  • 汕头网站搭建wordpress文章列表摘要
  • 网站开发体会800字网站开发新功能
  • 网站域名查询ip杭州pc网站开发公司有哪些
  • 青岛公司网站设计网站后台编辑器内容不显示
  • vc6.0做网站wordpress调用会员等级
  • 哪个网站有做商标网站的类型是什么意思
  • 网站 主机网站内容段落之间有空格对seo有影响吗
  • 网站的宣传推广学网站开发哪个好
  • 免费背景图片素材网站北京企业建站程序
  • 营销网站建设方案wordpress门户
  • 世界网站排名查询效果好企业营销型网站建设公司
  • 网站用户体验解决方案个人网页设计作品赏析
  • 常州网站建设方案外包网站开发用到的技术
  • 防伪网站模板如何找百度做网站
  • 网站建设与维护成绩查询云南app开发系统
  • 自己做网站的难度建设专门网站 强化信息宣传