1. 第2章 面试需要的基础知识
1.1. 面试题2:实现Singleton模式
题目:设计一个类,我们只能生成该类的一个实例
不好的解法一:只适用于单线程环境
/**
* @Author: maxwell_a@qq.com
* @Date: 2021-07-10 16:22
* @Version: 1.0
*/
public class Singleton1 {
private Singleton1(){
}
private static Singleton1 instance = null;
public static Singleton1 instance(){
if (instance == null){
instance = new Singleton1();
}
return instance;
}
}
不好的解法二:虽然在多线程环境中能工作,但效率不高
import java.util.concurrent.locks.ReentrantLock;
/**
* @Author: maxwell_a@qq.com
* @Date: 2021-07-10 16:22
* @Version: 1.0
*/
public class Singleton1 {
private static final ReentrantLock lock=new ReentrantLock();
private Singleton1(){
}
private static Singleton1 instance = null;
public static Singleton1 instance(){
// synchronized (instance){
// if (instance == null){
// instance = new Singleton1();
// }
// }
lock.lock();
try{
if (instance == null){
instance = new Singleton1();
}
}finally {
lock.unlock();
}
return instance;
}
}
可行的解法:加同步锁前后两次判断实例是否已存在
import java.util.concurrent.locks.ReentrantLock;
/**
* @Author: maxwell_a@qq.com
* @Date: 2021-07-10 16:34
* @Version: 1.0
*/
public class Singleton3 {
private static final ReentrantLock lock=new ReentrantLock();
private Singleton3(){
}
private static Singleton3 instance = null;
public static Singleton3 instance(){
if (instance==null){
lock.lock();
try{
if (instance == null){
instance = new Singleton3();
}
}finally {
lock.unlock();
}
}
return instance;
}
}
强烈推荐的解法一:利用静态构造函数(不能控制静态代码块的调用时机,降低内存的使用效率)
/**
* @Author: maxwell_a@qq.com
* @Date: 2021-07-10 16:39
* @Version: 1.0
*/
public class Singleton4 {
private Singleton4(){
}
private static Singleton4 instance = new Singleton4();
public static Singleton4 instance(){
return instance;
}
}
强烈推荐的解法二:实现按需创建实列
/**
* @Author: maxwell_a@qq.com
* @Date: 2021-07-10 16:44
* @Version: 1.0
*/
public class Singleton5 {
Singleton5(){
}
public static Singleton5 instance(){
return Nested.instance;
}
static class Nested{
static Singleton5 instance=new Singleton5();
}
}
补充:Java中内部类(静态和非静态)加载时间
/**
* @Author: maxwell_a@qq.com
* @Date: 2021-07-11 10:34
* @Version: 1.0
*/
public class OuterClass {
// public static void main(String[] args) {
// OuterClass outer=new OuterClass();
// System.out.println("外部类静态变量加载时间:\t"+OuterClass.OUTER_DATE);
// }
// public static void main(String[] args) {
// OuterClass outer = new OuterClass();
// InnerClass innerClass = outer.new InnerClass();
// System.out.println("非静态内部类加载时间:\t"+innerClass.INNER_DATE);
// }
public static void main(String[] args) {
System.out.println("静态内部类加载时间:\t\t"+InnerStaticClass.INNER_STATIC_DATE);
}
private static long OUTER_DATE=System.currentTimeMillis();
static{
System.out.println("外部类静态代码块加载时间:\t"+System.currentTimeMillis());
}
public OuterClass(){
System.out.println("外部类构造函数加载时间:\t"+System.currentTimeMillis());
}
static class InnerStaticClass{
public static long INNER_STATIC_DATE = System.currentTimeMillis();
static{
System.out.println("静态内部类静态块加载时间:\t"+System.currentTimeMillis());
}
}
class InnerClass{
public long INNER_DATE = System.currentTimeMillis();
public InnerClass(){
System.out.println("内部类加载时间:\t\t\t"+System.currentTimeMillis());
}
}
}
结论:内部类在使用的时候才被加载,类加载时顺序如下:静态代码块->构造函数,非静态内部类对象寄生在外部类对象中,外部类对象不依赖内部类对象;静态内部类与外部类是类相关的,静态内部类中有外部类的类引用。