Java单例模式
Java单例模式
1、饿汉模式:直接创建对象,不存在线程安全问题
1.1、直接实例化(简洁直观)
/**
* @author luojianhui
* @date 2018/11/2
* 直接实例化
* 1.构造器私有化
* 2.自行创建,并用静态变量保存
* 3.向外提供这个实例
* 4.强调这是一个单例,用final修改
* 5.随着类加载初始化,静态修饰对象也会创建
*/
public class Singleton1 {
public static final Singleton1 INGLETON=new Singleton1();
private Singleton1() {
}
}
1.2、枚举式(最简洁)(jdk 1.5之后)
/**
* @author luojianhui
* @date 2018/11/2
* 枚举式
* 1.枚举类型:表示该类型的对象是有限的几个
* 2.限定为一个,就成为单例了
*/
public enum Singleton2 {
INSTANCE
}
1.3、静态代码块(适合复杂实例化)
/**
* @author luojianhui
* @date 2018/11/2
* 静态代码块
* 1.随着类加载初始化,静态代码块也执行
*/
public class Singleton3 {
public static final Singleton3 SINGLETON;
private String info;
static {
try {
//初始化Properties
Properties pro = new Properties();
//文件最终编译是在类路径下
pro.load(Singleton3.class.getClassLoader().getResourceAsStream("singleton.properties"));
INGLETON = new Singleton3(pro.getProperty("info"));
} catch (IOException e) {
throw new RuntimeException();
}
}
private Singleton3(String info) {
this.info = info;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
@Override
public String toString() {
return "Singleton3{" +
"info='" + info + '\'' +
'}';
}
}
singleton.properties 放在src目录下
info=ash
测试:
public class TestDemo{
public static void main(String[] args) {
Singleton3 ingleton = Singleton3.INGLETON;
System.out.println(ingleton.toString());
//输出结果:Singleton3{info='ash'}
}
}
这种方式就像一些框架加载配置文件
2、懒汉模式:延迟创建对象
2.1、线程不安全(适用于单线程)
/**
* @author luojianhui
* @date 2018/11/2
*/
public class Singleton4 {
//静态变量保存唯一实例
private static Singleton4 singleton;
private Singleton4() {
}
public static Singleton4 getInstance() {
if (singleton == null) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
singleton = new Singleton4();
}
return singleton;
}
}
测试:
/**
* @author luojianhui
* @date 2018/9/12
*/
public class TestDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建线程
Callable<Singleton4> callable = new Callable<Singleton4>() {
@Override
public Singleton4 call() throws Exception {
return Singleton4.getInstance();
}
};
//创建两个线程池
ExecutorService es = Executors.newFixedThreadPool(2);
Future<Singleton4> f1 = es.submit(callable);
Future<Singleton4> f2 = es.submit(callable);
Singleton4 singleton4 = f1.get();
Singleton4 singleton41 = f2.get();
System.out.println(singleton4 == singleton41);
//输出结果:false
es.shutdown();
}
}
原因:当一个线程进入休眠,另一个线程此时判断singleton为null,两个线程都执行了if语句,所有创建了两个不能的实例
2.2、线程安全(适用于多线程)
/**
* @author luojianhui
* @date 2018/11/2
*/
public class Singleton5 {
//静态变量保存唯一实例
private static Singleton5 singleton;
private Singleton5() {
}
public static Singleton5 getInstance() {
//使用类作为锁对象
synchronized (Singleton5.class) {
if (singleton == null) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
singleton = new Singleton5();
}
return singleton;
}
}
}
锁
2.3、静态内部类形式(适用于多线程)
/**
* @author luojianhui
* @date 2018/11/2
* 在内部类被加载和初始化时,才创建实例对象
* 静态内部类不会自动随着外部类的加载和初始化而初始化,他是要单独去加载和初始化的
* 因为是在内部类加载和初始化时创建的,因此是线程安全的
*/
public class Singleton6 {
private Singleton6() {
}
private static class Inner {
private static final Singleton6 SINGLETON_6 = new Singleton6();
}
public static Singleton6 getInstance() {
return Inner.SINGLETON_6;
}
}