网站建设公司合同模板下载,天津营销型网站建设,wordpress申请网站,wordpress 3.7.1 下载强引用、弱引用、软引用、虚引用
Java执行 GC(垃圾回收)判断对象是否存活有两种方式#xff0c;分别是引用计数法和引用链法(可达性分析法)。 **引用计数#xff1a;**Java堆中给每个对象都有一个引用计数器#xff0c;每当某个对象在其它地方被引用时#xff0c;该对象的…强引用、弱引用、软引用、虚引用
Java执行 GC(垃圾回收)判断对象是否存活有两种方式分别是引用计数法和引用链法(可达性分析法)。 **引用计数**Java堆中给每个对象都有一个引用计数器每当某个对象在其它地方被引用时该对象的计数器 1引用失效则 -1 JDK 1.2版本开始对象的引用被划分为 4种级别使程序能更加灵活地控制对象的生命周期。这 4种级别由高到低依次为强引用、软引用、弱引用和虚引用。
强引用(StrongReference)
在一个线程内无须引用直接可以使用的对象强引用不会被JVM清理。我们平时申明变量使用的就是强引用普通系统99%以上都是强引 用比如String sHello World。
Java中的引用有点像 C的指针。通过引用可以对堆中的对象进行操作。在Java 程序中最常见的引用类型是强引用它也是默认的引用类型。例如StringBuffer strnew StringBuffer“Hello World”
强引用具备以下特点 **1**强引用可以直接访问目标对象。 **2**强引用所指向的对象在任何时候都不会被系统回收。JVM宁愿抛出Out Of Memory异常也不会回收强引用所指向的对象。 **3**强引用可能导致内存泄漏。
通常来说应用程序内部的内存泄露有两种情况。一种是虚拟机中存在程序无法使用的内存区域,另一种情况是程序中存在大量存活时间过长的对象。
(二) 软引用(SoftReference)
java中使用SoftRefence来表示软引用
软引用是除了强引用外最强的引用类型我们可以通过java.lang.ref.SoftReference使用软引用。一个持有软引用的对象它不会被JVM很快回收JVM会根据当前堆的使用情况来判断何时回收。当堆使用率临近阙值时才会去回收软引用的对象。只要有足够的内存软引用便可能在内存中存活相当长一段时间。通过软引用垃圾回收器就可以在内存不足时释放软引用可达的对象所占的内存空间。保证程序正常工作。 通过一个软引用申明JVM抛出OOM之前清理所有的软引用对象。垃圾回收器某个时刻决定回收软可达的对象的时候会清理软引用并可选的把引用存放到一个引用队列ReferenceQueue。
(三) 弱引用(WeakReference)
java中使用WeakReference来表示弱引用。如果某个对象与弱引用关联那么当JVM在进行垃圾回收时无论内存是否充足都会回收此类对象。
通过一个弱引用申明。类似弱引用只不过 Java 虚拟机会尽量让软引用的存活时间长一些迫不得已才清理。
(四) 虚引用(PhantomReference)
java中使用PhantomReference来表示虚引用。
通过一个虚引用申明。仅用来处理资源的清理问题比Object里面的finalize机制更灵活。get方法返回的永远是nullJava虚拟机不负责清理虚引用但是它会把虚引用放到引用队列里面。 Java中 4种引用的级别和强度由高到低依次为强引用 - 软引用 - 弱引用 - 虚引用 当垃圾回收器回收时某些对象会被回收某些不会被回收。垃圾回收器会从根对象 Object来标记存活的对象然后将某些不可达的对象和一些引用的对象进行回收。 ThreadLocal
1. 简介
ThreadLocal叫做线程变量意思是ThreadLocal中填充的变量属于当前线程该变量对其他线程而言是隔离的也就是说该变量是当前线程独有的变量。ThreadLocal为变量在每个线程中都创建了一个副本那么每个线程可以访问自己内部的副本变量。
ThreadLoal 变量线程局部变量同一个 ThreadLocal 所包含的对象在不同的 Thread 中有不同的副本。这里有几点需要注意
因为每个 Thread 内有自己的实例副本且该副本只能由当前 Thread 使用。这是也是 ThreadLocal 命名的由来。既然每个 Thread 有自己的实例副本且其它 Thread 不可访问那就不存在多线程间共享的问题。 ThreadLocal 提供了线程本地的实例。它与普通变量的区别在于每个使用该变量的线程都会初始化一个完全独立的实例副本。ThreadLocal 变量通常被private static修饰。当一个线程结束时它所使用的所有 ThreadLocal 相对的实例副本都可被回收。 总的来说ThreadLocal 适用于每个线程需要自己独立的实例且该实例需要在多个方法中被使用也即变量在线程间隔离而在方法或类间共享的场景 2. ThreadLocal与Synchronized的区别
ThreadLocal其实是与线程绑定的一个变量。ThreadLocal和Synchonized都用于解决多线程并发访问。
但是ThreadLocal与synchronized有本质的区别
Synchronized用于线程间的数据共享而ThreadLocal则用于线程间的数据隔离。Synchronized是利用锁的机制使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本使得每个线程在某一时间访问到的并不是同一个对象这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反它用于在多个线程间通信时能够获得数据共享。
2.1 一句话概括
一句话理解ThreadLocalthreadlocl是作为当前线程中属性ThreadLocalMap集合中的某一个Entry的key值Entrythreadlocl,value虽然不同的线程之间threadlocal这个key值是一样但是不同的线程所拥有的ThreadLocalMap是独一无二的也就是不同的线程间同一个ThreadLocalkey对应存储的值(value)不一样从而到达了线程间变量隔离的目的但是在同一个线程中这个value变量地址是一样的。
3. ThreadLocal 常见使用场景
如上文所述ThreadLocal 适用于如下两种场景
每个线程需要有自己单独的实例实例需要在多个方法中共享但不希望被多线程共享
对于第一点每个线程拥有自己实例实现它的方式很多。例如可以在线程内部构建一个单独的实例。ThreadLocal 可以以非常方便的形式满足该需求。
对于第二点可以在满足第一点每个线程有自己的实例的条件下通过方法间引用传递的形式实现。ThreadLocal 使得代码耦合度更低且实现更优雅。
4. 总结
前文我们讲过ThreadLocal的主要用途是实现线程间变量的隔离表面上他们使用的是同一个ThreadLocal 但是实际上使用的值value却是自己独有的一份。用一图直接表示threadlocal 的使用方式。 从图中我们可以当线程使用threadlocal 时是将threadlocal当做当前线程thread的属性ThreadLocalMap 中的一个Entry的key值实际上存放的变量是Entry的value值我们实际要使用的值是value值。value值为什么不存在并发问题呢因为它只有一个线程能访问不存在资源竞争.
Entry将ThreadLocal作为Key值作为value保存它继承自WeakReference注意构造函数里的第一行代码super(k)这意味着ThreadLocal对象是一个「弱引用」。可以看图1.
key是弱引用而value是强引用弱引用随着程序的运行会被垃圾回收掉而强引用不会
4.1 ThreadLocal使用注意点 避免读取到脏数据 现在代码中比较常见的使用到了线程池线程池中的线程是可重复利用的假设使用ThreadLocal 设置了value值如果没有进行remove操作下次该线程又被取到通过get方法取到的值是上次设置的value值。 处理方式: 使用完后进行remove操作。 避免内存泄漏 使用了线程池后由于线程一直存在, 对应的value值就不能被垃圾回收掉容易产生内存泄漏问题。 由于ThreadLocalMap 的生命周期跟 Thread 一样长对于重复利用的线程来说如果没有手动删除remove()方法对应 key 就会导致entry(nullvalue)的对象越来越多从而导致内存泄漏 处理方式: 使用完后进行remove操作。 将ThreadLocal变量定义成private static的这样的话ThreadLocal的生命周期就更长由于一直存在ThreadLocal的强引用所以ThreadLocal也就不会被回收也就能保证任何时候都能根据ThreadLocal的弱引用访问到Entry的value值然后remove它防止内存泄露。 cal的生命周期就更长由于一直存在ThreadLocal的强引用所以ThreadLocal也就不会被回收也就能保证任何时候都能根据ThreadLocal的弱引用访问到Entry的value值然后remove它防止内存泄露。
4.2 具体使用场景 存储用户登录Token 场景二、数据库连接处理数据库事务 场景三、数据跨层传递controller,service, dao 场景四、Spring使用ThreadLocal解决线程安全问题 我们知道在一般情况下只有无状态的Bean才可以在多线程环境下共享在Spring中绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等中非线程安全的“状态性对象”采用ThreadLocal进行封装让它们也成为线程安全的“状态性对象”因此有状态的Bean就能够以singleton的方式在多线程中正常工作了。