package net.csdn.se.singletondemo;
/**
* 线程安全的---懒汉式(懒加载)创建
*/
public class Singleton06 {
//1\
private Singleton06(){}
/**
* 2静态的内部类的方式来创建实例
* 在内部类被加载和初始化时,才创建实例。
* 静态内部类不会随着外部类的加载和初始化而初始化,而是在需要的时候才会进行加载和初始化
*/
private static class Inner{
private static Singleton06 INSTANCE = new Singleton06();
}
//3
public static Singleton06 getInstance(){
return Inner.INSTANCE;
}
public static void main(String[] args) {
Singleton06 instance = Singleton06.getInstance();
Singleton06 instance1 = Singleton06.getInstance();
System.out.println(instance == instance1);//结果一直为True
}
}

- 饿汉式创建三种方式
package net.csdn.se.singletondemo;
/**
* 饿汉式直接创建单例
* 1、只能创建一个实例 ---> 构造方法私有化
* 2、创建出来的实例进行保存
* 3、对外暴露
* 总结:
* 1、优点:基于classloader机制来创建的单例,没有不加锁执行效率高、但是也避免了线程安全问题
* 2、缺点:类加载时即初始化了实例,因此没有达到lazyloading(延迟加载)的效果对于那些创建出来没有被使用的也没有被回收的类来说,导致浪费内存空间
*/
public class Singleton01 {
//1. 第一步,构造方法私有化,只创建一个实例
private Singleton01(){}
//2. 第二步,对创建出来的实例进行保存
private static Singleton01 INSTANCE = new Singleton01();
//3、第三步 对外进行暴露
public Singleton01 getInstance(){
return INSTANCE;
}
}
package net.csdn.se.singletondemo;
/**
* 饿汉式 枚举的方式创建单例
* 特点:
* 代码简单,实现容易
*/
public enum Singleton02 {
INSTANCE;
}
class Singleton02Test{
public static void main(String[] args) {
Singleton02 instance = Singleton02.INSTANCE;
}
}
package net.csdn.se.singletondemo;
import javax.sound.midi.Soundbank;
import java.io.IOException;
import java.util.Properties;
/**
* 饿汉式实例
* 使用静态代码块的方式创建单例
*/
public class Singleton03 {
//2\ 第二要素 进行保存
private static Singleton03 INSTANCE; //
static {
INSTANCE = new Singleton03(); //类加载的时候 可以写业务逻辑
//加载配置文件
Properties properties = new Properties();
try {
properties.load(Singleton03.class.getClassLoader().getResourceAsStream("jdbc.properties"));
String username = properties.getProperty("userName");
String password = properties.getProperty("password");
System.out.println(username);
System.out.println(password);
} catch (IOException e) {
e.printStackTrace();
}
}
//1 第一要素 构造方法私有化
private Singleton03(){}
//3 对外暴露
public static Singleton03 getInstance(){
return INSTANCE;
}
public static void main(String[] args) {
Singleton03 instance = Singleton03.getInstance();
Singleton03 instance2 = Singleton03.getInstance();
System.out.println(instance == instance2);
}
}
- 懒汉式创建三种方式
package net.csdn.se.singletondemo;
import java.awt.*;
/**
* 线程不安全的方式创建单例---懒汉式
* 线程安全的方式创建单例 添加synchronized----懒汉式
* 优点:layloading,第一次调用的使用才初始化,避免了内存的浪费
* 缺点:必须加锁才能保证是单例的,影响了效率
*/
public class Singleton04 {
private static Singleton04 INSTANCE;
private Singleton04(){}
// public static Singleton04 getInstance(){ 线程不安全创建方式
public static synchronized Singleton04 getInstance(){ //线程安全创建方式
if(INSTANCE == null){ //
INSTANCE = new Singleton04();
}
return INSTANCE;
}
}
package net.csdn.se.singletondemo;
/**
* 线程安全的---懒汉式(懒加载)创建
* 静态内部类不能传递参数
*/
public class Singleton06 {
//1\
private Singleton06(){}
/**
* 2静态的内部类的方式来创建实例
* 在内部类被加载和初始化时,才创建实例。
* 静态内部类不会随着外部类的加载和初始化而初始化,而是在需要的时候才会进行加载和初始化
/**
* 2静态的内部类的方式来创建实例
静态内部类的优点是:外部类加载时并不需要立即加载内部类,
内部类不被加载则不去初始化INSTANCE,故而不占内存。
即当SingleTon第一次被加载时,并不需要去加载SingleTonHoler,只有当getInstance()方法第一次被调用时,
才会去初始化INSTANCE,第一次调用getInstance()方法会导致虚拟机加载SingleTonHoler类,
这种方法不仅能确保线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。
那么,静态内部类又是如何实现线程安全的呢?
getInstance()方法,Inner.INSTANCE,取的是Inner里的INSTANCE对象,
跟上面那个DCL方法不同的是,getInstance()方法并没有多次去new对象,
故不管多少个线程去调用getInstance()方法,取的都是同一个INSTANCE对象,
而不用去重新创建。当getInstance()方法被调用时,Inner才在Singleton06的运行时常量池里,
把符号引用替换为直接引用,这时静态对象INSTANCE也真正被创建,然后再被getInstance()方法返回出去,
这点同饿汉模式。那么INSTANCE在创建过程中又是如何保证线程安全的呢?在《深入理解JAVA虚拟机》中,有这么一句话:
虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>()方法,其他线程都需要阻塞等待,直到活动线程执行<clinit>()方法完毕。如果在一个类的<clinit>()方法中有耗时很长的操作,就可能造成多个进程阻塞(需要注意的是,其他线程虽然会被阻塞,但如果执行<clinit>()方法后,其他线程唤醒之后不会再次进入<clinit>()方法。同一个加载器下,一个类型只会初始化一次。),在实际应用中,这种阻塞往往是很隐蔽的。
故而,可以看出INSTANCE在创建过程中是线程安全的,所以说静态内部类形式的单例可保证线程安全,也能保证单例的唯一性,同时也延迟了单例的实例化。
*/
*/
private static class Inner{
private static Singleton06 INSTANCE = new Singleton06();
}
//3
public static Singleton06 getInstance(){
return Inner.INSTANCE;
}
public static void main(String[] args) {
Singleton06 instance = Singleton06.getInstance();
Singleton06 instance1 = Singleton06.getInstance();
System.out.println(instance == instance1);//结果一直为True
}
}