一、饿汉式:静态变量
优点:
写法简单,在类装载的时候完成实例化,避免线程同步问题。
缺点:
在类装载的时候完成实例化,没有达到 lazy loading,如果一直没有使用过这个实例,则会造成内存的浪费。
class Singleton {
//私有化构造函数
private Singleton01(){
}
//内部创建对象实例
private final static Singleton01 instance = new Singleton01();
public static Singleton01 getInstance(){
return instance;
}
}
/**
*饿汉式:静态变量
*
*/
public class HungryManStaticConstant {
public static void main(String[] args) {
Singleton singleton1 = Singleton.getInstance();
Singleton singleton11 = Singleton.getInstance();
System.out.println(singleton1 == singleton11);
}
}
二、饿汉式:静态代码块
public class HungryManStaticCodeBlock02 {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
Singleton singleton1 = Singleton.getInstance();
System.out.println(singleton == singleton1);
}
}
class Singleton {
private Singleton(){
}
private static Singleton instance;
static {
instance = new Singleton();
}
public static Singleton getInstance(){
return instance;
}
}
三、懒汉式:线程不安全
/**
* 启动:
* 起到了Lazy Loading的效果,但是只能在单线程下使用
*
*/
public class LazyStyleThreadInsecurity03 {
public static void main(String[] args) {
Singleton03 singleton = Singleton.getInstance();
Singleton03 singleton1 = Singleton.getInstance();
System.out.println(singleton == singleton1);
System.out.println("singleton.hashCode=" + singleton.hashCode());
System.out.println("singleton1.hashCode=" + singleton1.hashCode());
Set<String> s = new HashSet<>();
//证明线程不安全
for (int i = 1; i <= 600 ; i++) {
new Thread(()->{
System.out.println(Singleton.getInstance().hashCode());
//s.add(String.valueOf(Singleton.getInstance().hashCode()));
}).start();
}
//System.out.println(s.size());
}
}
class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
四、懒汉式:同步方法
package com.hy.designpattern.singleton;
import java.util.HashSet;
import java.util.Set;
/**
* 效率低
*
*/
public class LazyStyleThreadSecuritySyncFunction {
public static void main(String[] args) {
System.out.println("懒汉式,线程安全");
System.out.println(Singleton.getInstance() == Singleton.getInstance());
Set<String> s = new HashSet<>();
for (int i = 0; i < 1000; i++) {
s.add(String.valueOf(Singleton.getInstance().hashCode()));
}
System.out.println(s.size());
}
}
class Singleton {
private Singleton(){
}
private volatile static Singleton instance;
public static synchronized Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
五、懒汉式:同步代码块
package com.hy.designpattern.singleton;
import java.util.HashSet;
import java.util.Set;
public class LazyStyleThreadSecuritySyncCodeBlock {
public static void main(String[] args) {
System.out.println("懒汉式,线程安全,同步代码块");
System.out.println(Singleton.getInstance() == Singleton.getInstance());
Set<String> s = new HashSet<>();
for (int i = 0; i < 1000; i++) {
s.add(String.valueOf(Singleton.getInstance().hashCode()));
}
System.out.println(s.size());
}
}
class Singleton {
private Singleton(){
}
private volatile static Singleton instance;
public static Singleton getInstance(){
if (instance == null){
synchronized (Singleton.class){
instance = new Singleton();
}
}
return instance;
}
}
六、双重验证
package com.hy.designpattern.singleton;
/**
* 双重检查
* 多线程开发中经常用到,先进行一次null判断,之后同步块内在判断一次null
* 优点:
* 如果对象未创建,多线程同时争抢获取实例方法,判断为null,线程开始等待阻塞,
* 当首先进入实例化对象的线程实例化完对象之后,之后已经判断过一次的线程开始争抢,争抢
* 上之后判断不为null推出,为进入第一次判断的线程直接不能进入同步块。
* 避免了反复进行方法同步。
* 线程安全、延迟加载、效率较高。
*
* 推荐使用
*/
public class DoubleCheck {
public static void main(String[] args) {
System.out.println("双重检查");
Singleton singleton = Singleton.getInstance();
Singleton singleton1 = Singleton.getInstance();
System.out.println(singleton1 == singleton);
System.out.println(singleton1.hashCode());
System.out.println(singleton.hashCode());
}
}
class Singleton {
private static volatile Singleton instance;
private Singleton(){
}
public static synchronized Singleton getInstance() {
if (instance == null){
synchronized (Singleton.class){
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
七、静态内部类
package com.hy.designpattern.singleton;
/**
* 采用类装载机制来保证初始化实例时只有一个线程。
*
* 静态内部类 在Singleton06被装载时并不会立即实例化,而是在需要实例化时,调用geyInstance,
*才会装载SingletonInstance类,从而完成Singleton的实例化
* 类的静态属性只会在第一次加载类的时候初始化,所以,JVM帮助我们保障了线程的安全性,在类进行初始化时
*别的线程时无法进入的
* 优点:
* 避免了线程安全,利用静态内部类的特性实现了延迟加载,效率高
*
* 推荐使用
*/
public class StaticInternalClass {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
Singleton singleton1 = Singleton.getInstance();
System.out.println(singleton == singleton1);
System.out.println(singleton.hashCode());
System.out.println(singleton1.hashCode());
}
}
class Singleton {
private static volatile Singleton instance;
private Singleton() {
}
private static class SingleInstance {
private static final Singleton INSTANCE = new Singleton();
}
public static synchronized Singleton getInstance() {
return SingleInstance.INSTANCE;
}
}
八、枚举
package com.hy.designpattern.singleton;
public class Enum {
public static void main(String[] args) {
Singleton singleton = Singleton.INSTANCE;
Singleton singleton1 = Singleton.INSTANCE;
System.out.println(singleton == singleton1);
System.out.println(singleton.hashCode());
System.out.println(singleton1.hashCode());
}
}
enum Singleton {
INSTANCE; //属性
public void sayOK() {
System.out.println("完成了");
}
}