Java单例模式
饿汉式
- 类初始化时创建对象,不管需不需要实例对象,都会创建
- 不存在线程安全问题,因为实例是在类创建和初始化时创建,是由类加载器完成的,类加载器是线程安全的
书写
(1)构造器私有化
(2)自行创建,并且用静态变量保存
(3)向外提供这个实例
(4)强调这是一个静态的,可以使用final修饰
直接方式
// 简洁直观
public class Singleton1 {
private Singleton1(){}
public static final Singleton1 INSTANCE = new Singleton1();
}
枚举式
// 最简洁
public enum Singleton2 {
INSTANCE;
}
静态代码块方式
// 适合复杂的实例化
class A {
static final String info = "password";
}
public class Singleton3_test {
public String info;
private Singleton3(String info) {
this.info = info;
}
static {
// 从其他地方获取的值
String val = A.info;
INSTANCE = new Singleton3_test(val);
}
public static final Singleton3_test INSTANCE;
@Override
public String toString() {
return "Singleton3{" +
"info='" + info + '\'' +
'}';
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
测试
public class Test1 {
public static void main(String[] args) {
System.out.println(Singleton1.INSTANCE);
System.out.println(Singleton2.INSTANCE.getClass());
System.out.println(Singleton3.INSTANCE);
}
}
/* 结果
Singleton1@1b6d3586
class Singleton2
Singleton3{info='password'}
*/
懒汉式
延迟创建实例对象,需要时才去创建对象,否则不创建
书写
(1)构造器私有化
(2)用一个静态变量保存这个唯一的实例
(3)提供一个静态方法,获取这个实例对象
线程不安全(适用于单线程)
public class SingletonLan1 {
private SingletonLan1(){}
private static SingletonLan1 instance;
public static SingletonLan1 getInstance(){
if (instance == null){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new SingletonLan1();
}
return instance;
}
}
// 测试
public class Lan_Test1 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<SingletonLan1> call = new Callable<SingletonLan1>() {
@Override
public SingletonLan1 call() throws Exception {
return SingletonLan1.getInstance();
}
};
ExecutorService es = Executors.newFixedThreadPool(2);
Future<SingletonLan1> f1 = es.submit(call);
Future<SingletonLan1> f2 = es.submit(call);
SingletonLan1 s1 = f1.get();
SingletonLan1 s2 = f2.get();
es.shutdown();
System.out.println(s1 == s2);
System.out.println(s1);
System.out.println(s2);
}
}
线程安全(适用于多线程)
public class SingletonLan2 {
private SingletonLan2(){}
private static SingletonLan2 instance;
public static SingletonLan2 getInstance(){
if (instance == null){
synchronized (SingletonLan2.class){
if (instance == null) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new SingletonLan2();
}
}
}
return instance;
}
}
// 测试
public class Lan_Test2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<SingletonLan2> call = new Callable<SingletonLan2>() {
@Override
public SingletonLan2 call() throws Exception {
return SingletonLan2.getInstance();
}
};
ExecutorService es = Executors.newFixedThreadPool(2);
Future<SingletonLan2> f1 = es.submit(call);
Future<SingletonLan2> f2 = es.submit(call);
SingletonLan2 s1 = f1.get();
SingletonLan2 s2 = f2.get();
es.shutdown();
System.out.println(s1 == s2);
System.out.println(s1);
System.out.println(s2);
}
}
静态内部类方式(适用于多线程)
- 在内部类被加载和创建时,才去创建实例对象
- 静态内部类不会随着外部类的加载和初始化而初始化,它是要单独加载和初始化的
- 因为是内部类创建和初始化时,创建的对象,所以不存在线程安全问题
// 相比上一种方法,简洁许多
public class SingletonLan3 {
private SingletonLan3(){}
private static class Inner{
private static final SingletonLan3 INSTANCE = new SingletonLan3();
}
public static SingletonLan3 getInstance(){
return Inner.INSTANCE;
}
}