/*
面向对象的三大特性:封装性,继承性以及多态性
单例设计模式:(封装性)
1、构造方法私有化
2、声明一个本类对象(私有并且静态)
3、给外部提供一个静态方法获取对象实例(私有并且静态)
1、饿汉模式:在第一次调用getInstance方法时,对象被创建,到程序结束后释放
2、懒汉模式:在类被加载后,对象被创建,到程序结束后释放
在项目中为什么要使用单例,单例有什么好处呢?
1、在设计一些工具类的时候(通常工具类,只有功能方法,没有属性)
2、工具类可能被频繁使用
目的是为了节省重复创建带来的内存消耗,从而提高效率
*/
public class FaceObject implements Serializable {//让单例类可以被序列化
public static void main(String[] args) {
Singleton s = Singleton.getInstance();
s.method();
Singleton s2 = Singleton.getInstance();
s2.method();
System.out.println(s == s2);
int i =Math.max(0,127);
System.out.println(i);
}
//饿汉模式单例
static class Singleton {
private Singleton(){}//构造方法私有化
private static Singleton s =new Singleton();//创建本类对象
private static Singleton getInstance(){//提供一个获取本类对象的方法(私有并且静态)
return s;
}
public void method(){
System.out.println("饿汉单例模式运行");
}
}
//懒汉模式单例
static class Singleton2 {
private Singleton2() {
if(s2!=null){//防止反射调用私有构造方法
throw new RuntimeException("此类对象为单例模式,已经被实例化了");
}
}
private volatile static Singleton2 s2=null;//加上volatile关键字保证变量的一致性
private static Singleton2 getInstance() {
//双重判断解决多线程问题
if (s2 == null) {//第一次判断是判断是否已经创建了对象
synchronized (Singleton2.class) {//加锁,解决线程安全的问题
if (s2 == null) {//是抢到第一次cpu时间片的线程用来判断是否已经创建对象
s2 = new Singleton2();
}
}
}
return s2;
}
}
}
/**
* DCL 懒汉模式单例(加强版)
* */
public class LazyMan {
private static boolean token=false;
private LazyMan(){
//加锁防止使用反射来破坏异常
synchronized (LazyMan.class){
if(token){//token是防止两次反射创建对象
throw new RuntimeException("禁止使用反射破坏单例");
}else {
token=true;
}
}
// System.out.println(Thread.currentThread().getName()+"ok");
}
//加volatile防止指令重排(在 lazyMan=new LazyMan(); 可能发生,浪费内存)
private volatile static LazyMan lazyMan;
public static LazyMan getInstance(){
if(lazyMan==null){
//加锁
synchronized (LazyMan.class){
//二次判断
if(lazyMan==null){
lazyMan=new LazyMan();//不是原子操作
/**
* 1、分配内存空间
* 2、执行构造方法
* 3、引用对象指向内存空间
* */
}
}
}
return lazyMan;
}
}