加入收藏 | 设为首页 | 会员中心 | 我要投稿 汽车网 (https://www.0577qiche.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 教程 > 正文

Java 中的引用类型和使用场景

发布时间:2023-04-18 14:20:36 所属栏目:教程 来源:
导读:Java 中的引用类型和使用场景 作者:Grey 原文地址: 博客园:Java 中的引用类型和使用场景 CSDN:Java 中的引用类型和使用场景 Java中的引用类型分成「强引用」,「软引用」, 「

Java中的引用类型分成「强引用」
Java 中的引用类型和使用场景 作者:Grey 原文地址: 博客园:Java 中的引用类型和使用场景 CSDN:Java 中的引用类型和使用场景 Java中的引用类型分成「强引用」,「软引用」, 「

Java中的引用类型分成「强引用」,「软引用」, 「弱引用」, 「虚引用」。

强引用
没有引用指向这个对象,垃圾回收会回收,例如:

package git.snippets.juc;
import java.io.IOException;
public class normalRef {
    public static void main(String[] args) throws IOException {
        M m = new M();
        m = null;
        System.gc();
        system.in.read();
    }
    static class M {
        M() {}
        @Override
        protected void finalize() throws Throwable {
            System.out.println("finalized");
        }
    }
}
软引用
当有一个对象被一个软引用所指向的时候,只有系统内存不够用的时候,才会被回收,可以用做缓存(比如缓存大图片)

示例代码:

注:执行以下方法的时候,需要把VM options设置为-xms20M -Xmx20M。

package git.snippets.juc;
import java.io.IOException;
import java.lang.ref.softReference;
import java.util.concurrent.TimeUnit;
/**
 * heap将装不下,这时候系统会垃圾回收,先回收一次,如果不够,会把软引用干掉
 * 软引用,适合做缓存
 * 示例需要把Vm options设置为:-xms20M -Xmx20M
 */
public class SoftRef {
    public static void main(String[] args) throws IOException {
        SoftReference<byte[]> reference = new SoftReference<>(new byte[1024 * 1024 * 10]);
        System.out.println(reference.get());
        System.gc();
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printstacktrace();
        }
        System.out.println(reference.get());
        byte[] bytes = new byte[1024 * 1024 * 10];
        System.out.println(reference.get());
        system.in.read();
    }
}
上述代码在第一次执行System.out.println(reference.get())时候,由于堆的最大最小值都是20M,而我们分配的byte数组是10M,没有超过最大堆内存,所以执行垃圾回收,软引用不被回收;后续又调用了byte[] bytes = new byte[1024 * 1024 * 10];再次分配了10M内存,此时堆内存已经超过设置的最大值,会进行回收,所以最后一步的System.out.println(reference.get());无法get到数据。

弱引用
只要垃圾回收,就会回收。如果有一个强引用指向弱引用中的这个对象,如果这个强引用消失,这个对象就应该被回收。一般用在容器里面。

示例:

package git.snippets.juc;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
/**
 * 弱引用遭到gc就会回收
 * ThreadLocal应用,缓存应用,WeakHashMap
 */
public class WeakRef {
    public static void main(String[] args) {
        WeakReference<T> reference = new WeakReference<>(new T());
        System.out.println(reference.get());
        System.gc();
        System.out.println(reference.get());
    }
    static class T {
        T() {}
        @Override
        protected void finalize() {
            System.out.println("finalized");
        }
    }
}
如果执行了一次GC,reference.get() 获取到的值即为空。

弱引用的使用场景
弱引用的一个典型应用场景就是ThreadLocal,以下是ThreadLocal的的简要介绍

set方法

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalmap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
get方法

    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();
    }
ThreadLocalmap是当前线程的一个成员变量,所以,其他线程无法读取当前线程设置的ThreadLocal值。

ThreadLocal.ThreadLocalmap threadLocals = null;
ThreadLocal的主要应用场景

场景一:每个线程需要一个独享的对象:假设有100个线程都需要用到SimpleDateFormat类来处理日期格式,如果共用一个SimpleDateFormat,就会出现线程安全问题,导致数据出错,如果加锁,就会降低性能,此时使用ThreadLocal,给每个线程保存一份自己的本地SimpleDateFormat,就可以同时保证线程安全和性能需求。

场景二:每个线程内部保存全局变量,避免传参麻烦:假设一个线程的作用是拿到前端用户信息,逐层执行Service1,Service2,Service3,Service4层的业务逻辑,其中每个业务层都会用到用户信息,此时一个解决办法就是将User信息对象作为参数层层传递,但是这样会导致代码冗余且不利于维护。此时可以将User信息对象放入当前线程的Threadlocal中,就变成了全局变量,在每一层业务层中,需要使用的时候直接从Threadlocal中获取即可。

场景三:Spring的声明式事务,数据库连接写在配置文件,多个方法可以支持一个完整的事务,保证多个方法是用的同一个数据库连接(其实就是放在ThreadLocal里面)

了解了ThreadLocal简要介绍以后,我们可以深入理解一下ThreadLocal的一个内部原理,前面提到,ThreadLocal的set方法实际上是往当前线程的一个threadLocals表中插入一条记录,而这个表中的记录都存在一个Entry对象中,这个对象有一个key和一个value,key就是当前线程的ThreadLocal对象。

static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

(编辑:汽车网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章