1.单例的常见形式
2.饿汉式
类一被加载就创建对象,不管是否需要。创建的很着急,所以称为饿汉式。
2.1直接实例化
package singleton;
/*饿汉式:直接创建实例对象,不管你需不需要都会创建(因为static关键字)
*特点如下:
* 1.构造器私有化
* 2.自行创建,并且用静态变量保存
* 3.向外提供这个实例
* 4.可以通过final关键字强调这是一个单例
*
* 缺点:
* 1.实例对象不管你需不需要都会创建,浪费资源
*
*/
public class Singleton01 {
public static final Singleton01 SINGLETON_01 =new Singleton01();
private Singleton01() {
}
public void say(){
System.out.println("Singleton01.say()");
}
}
2.2 枚举(其实简单)
package singleton;
/*
*枚举类型:表示该类型的对象是有限的几个
* 我们可以限定为一个,就成了单例
*/
public enum Singleton02 {
INSTANCE;
public void say(){
System.out.println("enum");
}
}
2.3 静态代码块
2.3.1 简单版
package singleton;
/**
*若构造方法有参 则使用静态代码块较好
* 否则 还是使用简单单例
*/
public class Singleton03 {
public static final Singleton03 SINGLETON_03;
private String info;
static {
SINGLETON_03=new Singleton03("name") ;
// 报错:this和super关键字不能在static修饰的内容中使用
// SINGLETON_03=new Singleton03(this.info) ;
}
private Singleton03(String info){
this.info=info;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
2.3.2 升级版(从配置文件读入)
package singleton;
import java.io.IOException;
import java.util.Properties;
/**
* 使用配置文件读入参数
*/
public class Singleton03Plus {
public static final Singleton03Plus SINGLETON_03_PLUS;
private String name;
private String age;
static {
try {
// 配置文件放在Resource文件夹下
Properties properties = new Properties();
properties.load(Singleton03Plus.class.getClassLoader().getResourceAsStream("single.properties"));
SINGLETON_03_PLUS = new Singleton03Plus(properties.getProperty("name"), properties.getProperty("age"));
System.out.println(properties);
} catch (IOException e) {
// 一定要抛出这个异常
throw new RuntimeException(e);
}
}
private Singleton03Plus(String name, String age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "Singleton03Plus{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
2.3.3 配置文件single.properties内容
info=xiongdu
name=zhangsan
age=12
3 懒汉式
懒汉式:延迟创建该实例对象(在需要的时候创建(第一次需要时创建))
3.1 线程不安全
package singleton.singleton2;
/**
* 懒汉式:延迟创建该实例对象(在需要的时候创建(第一次需要时创建))
*特点:
* 1.构造器私有化
* 2.用一个静态变量保存这个唯一的实例
* 3.提供一个静态方法,创建或获取这个实例
*
*/
public class Singleton1 {
private static Singleton1 singleton1;
private Singleton1(){
}
public static Singleton1 getInstance(){
if(singleton1==null) {
singleton1 = new Singleton1();
}
return singleton1;
}
}
3.2 线程安全
package singleton.singleton2;
/*
*加锁实现线程安全
*/
public class Singleton2 {
private static Singleton2 singleton2;
private Singleton2(){
}
public static Singleton2 getInstance(){
if(singleton2==null){
synchronized (Singleton2.class){
//双重验证 保证线程安全
if(singleton2==null){
singleton2=new Singleton2();
}
}
}
return singleton2;
}
}
3.3 静态内部类(推荐使用)
package singleton.singleton2;
/**
* 推荐使用:
*
* 1.在内部类被加载和初始化时,才创建实例对象
* 2.静态内部类不会自动随着外部类的加载和初始化而初始化,它是要单独去加载和初始化的
* 3.因为是在内部类加载和初始化的,创建的,因此是线城安全的
*/
public class Singleton3 {
private Singleton3(){
}
private static class Inner{
private static final Singleton3 SINGLETON_3=new Singleton3();
}
public static Singleton3 getInstance(){
return Inner.SINGLETON_3;
}
}
3.4 多线程测试
package singleton.singleton2;
import java.util.concurrent.*;
public class TestSingleton2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<Singleton2> c = new Callable<Singleton2>() {
@Override
public Singleton2 call() throws Exception {
return Singleton2.getInstance();
}
};
ExecutorService es = Executors.newFixedThreadPool(2);
Future<Singleton2> f1 = es.submit(c);
Future<Singleton2> f2 = es.submit(c);
Singleton2 s1 = f1.get();
Singleton2 s2 = f2.get();
System.out.println("s1==s2 = " + (s1 == s2));
System.out.println("s1 = " + s1);
System.out.println("s2 = " + s2);
es.shutdown();
}
}