Java面试题

Posted by Kaka Blog on February 22, 2021

互联网三高:高可用、高扩展、高性能

高性能:低延迟(响应快),高并发(高吞吐量)

Amdahl定律:想要显著加速整个系统,必须提升全系统中相当大的部分的速度。

单机高性能:

  1. 提高响应时间
  2. 提高吞吐量(增加线程)

多线程

synchronized

synchronized(t):并行变串行,给t加锁会修改t对象的markword,非公平锁,需要和操作系统打交道,涉及到线程切换。

JOL:Java Object Layout

ClassLayout.parseInstance().toPrintable()可打印对象在内存里的存储

JDK1.5后增加了JUC,核心是CAS和AQS

CAS

CAS:如果要修改的值和期望的值一样,则修改成功,否则重新读取再修改,属于自旋锁,会消耗CPU资源。

  • ABA问题:正常没有问题,如果是引用类型,则需要解决。增加版本解决。
  • 原子性:必须保证比较和操作的原子性。最终实现是通过一条汇编指令:lock comxchg。comxchg并不能保证原子性,需要靠lock锁总线实现。

Java中的4中引用类型

java对象的引用包括强引用,软引用,弱引用,虚引用。

1. 强引用

这种引用是平时开发中最常用的,例如 String strong = new String(“Strong Reference”),当一个实例对象具有强引用时,垃圾回收器不会回收该对象,当内存不足时,宁愿抛出OutOfMemeryError异常也不会通过回收强引用的对象,因为JVM认为强引用的对象是用户正在使用的对象,它无法分辨出到底该回收哪个,强行回收有可能导致系统严重错误。

2. 软引用(SoftReference)

如果一个对象具有软引用,内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存,比如网页缓存、图片缓存等。使用软引用能防止内存泄露,增强程序的健壮性。

SoftReference<Book> softReference = new SoftReference<>(new Book());
Book book = softReference.get();

一旦SoftReference保存了对一个Java对象的软引用后,在垃圾线程对 这个Java对象回收前,SoftReference类所提供的get()方法返回Java对象的强引用。另外,一旦垃圾线程回收该Java对象之 后,get()方法将返回null。

3. 弱引用(WeakReference)

只有弱引用的对象,当JVM触发gc时,就会回收该对象。与软引用不同的是,不管是否内存不足,弱引用都会被回收。弱引用可以结合ReferenceQueue来使用,当由于系统触发gc,导致软引用的对象被回收了,JVM会把这个弱引用加入到与之相关联的ReferenceQueue中,不过由于垃圾收集器线程的优先级很低,所以弱引用不一定会被很快回收。

ReferenceQueue referenceQueue = new ReferenceQueue();
WeakReference<Book> weakReference = new WeakReference(new Book(), referenceQueue);
Book book = softReference.get();
System.gc();
//Runtime.getRuntime().gc();
Reference reference = referenceQueue.poll();

在静态内部类中,经常会使用虚引用。例如:一个类发送网络请求,承担 callback 的静态内部类,则常以虚引用的方式来保存外部类的引用,当外部类需要被 JVM 回收时,不会因为网络请求没有及时回应,引起内存泄漏。

4. 虚引用(PhantomReference)

如果一个对象只有虚引用在引用它,垃圾回收器是可以在任意时候对其进行回收的,虚引用主要用来跟踪对象被垃圾回收器回收的活动,当被回收时,JVM会把这个弱引用加入到与之相关联的ReferenceQueue中。与软引用和弱引用不同的是,虚引用必须有一个与之关联的ReferenceQueue。

PhantomReference<Book> phantomReference = new PhantomReference<>(new Book(), referenceQueue);
Book book = phantomReference.get(); //此值为null
Reference reference = referenceQueue.poll();

一般可以通过虚引用达到回收一些非java内的一些资源比如堆外内存的行为。例如:在 DirectByteBuffer 中,会创建一个 PhantomReference 的子类Cleaner的虚引用实例用来引用该 DirectByteBuffer 实例,Cleaner 创建时会添加一个 Runnable 实例,当被引用的 DirectByteBuffer 对象不可达被垃圾回收时,将会执行 Cleaner 实例内部的 Runnable 实例的 run 方法,用来回收堆外资源。

泛型

泛型有三类,分别为:泛型类、泛型接口、泛型方法。

泛型类:

class name<T1, T2, ..., Tn> { /* ... */ }

泛型接口

泛型接口的声明与泛型类一致,泛型接口语法形式:

public interface Context<T> {
    T getContext();
}

泛型方法

泛型方法可以是普通方法、静态方法、抽象方法、final修饰的方法以及构造方法。

public <T> T func(T obj) {}

参考资料