最简单的设计模式,这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。这种类只能new出一个对象。
我觉得最简单的写法,缺点也不突出。
在类中创建一个静态对象,使用public方法来访问对象。
//饿汉式
public class Mgr {
//创建单例对象
private static final Mgr mgr = new Mgr();
//构造方法私有
private Mgr() {
}
//通过public方法访问对象
public static Mgr GetMgr() {
return mgr;
}
public static void main(String[] args) {
//创建单例对象
Mgr mgr = Mgr.GetMgr();
}
}
线程不安全
在实例化的时候判断对象是否实例化,
如果没有,则创建对象,
如果有,返回对象
/*
懒汉式
在实例化的时候判断对象是否实例化,
如果没有,则创建对象,
如果有,返回对象
*/
public class Mgr {
//此处不能使用final关键字,否则不能改变
public static Mgr mgr = null;
private Mgr() {
}
//判断mgr是否为空
public static Mgr getMgr() {
if(mgr==null) {
mgr = new Mgr();
return mgr;
}
else return mgr;
}
public static void main(String[] args) {
//创建单例对象
Mgr mgr = Mgr.getMgr();
}
}
但是这种写法是不安全的,当使用多线程的时候,执行到if(mgr == null),还没有创建对象的时候,另一线程也执行if(mgr==null),所以就导致创建了多个对象。
import static java.lang.Thread.sleep;
/*
懒汉式
在调用的时候判断对象是否实例化,
如果没有,则创建对象,
如果有,返回对象
*/
public class Mgr {
//此处不能使用final关键字,否则不能改变
public static Mgr mgr = null;
private Mgr() {
}
//判断mgr是否为空
public static Mgr getMgr() {
if(mgr==null) {
//在此处有操作延迟一部分时间1
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
mgr = new Mgr();
return mgr;
}
else return mgr;
}
public static void main(String[] args) {
//多线程创建单例对象
for(int i=1; i<100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
Mgr mgr = Mgr.getMgr();
System.out.println(mgr);
}
}).start();}
}
}
可以看到输出的地址中并不是所有的都是一致的。

解决懒汉式的线程安全问题
在getMgr()前加锁,使其成为同步方法
import static java.lang.Thread.sleep;
/*
懒汉式
在调用的时候判断对象是否实例化,
如果没有,则创建对象,
如果有,返回对象
*/
public class Mgr {
public static Mgr mgr = null;
private Mgr() {
}
//判断mgr是否为空
public static synchronized Mgr getMgr() {
if(mgr==null) {
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
mgr = new Mgr();
return mgr;
}
else return mgr;
}
public static void main(String[] args) {
//多线程创建单例对象
for(int i=1; i<100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
Mgr mgr = Mgr.getMgr();
System.out.println(mgr);
}
}).start();}
}
}

同步方法的效率太低,所以有了加双重锁的方式。
这里的两次判断是否为空是有必要的,因为可能会有多个线程通过第一层判断。
import static java.lang.Thread.sleep;
/*
懒汉式
在调用的时候判断对象是否实例化,
如果没有,则创建对象,
如果有,返回对象
*/
public class Mgr {
public static Mgr mgr = null;
private Mgr() {
}
//判断mgr是否为空
public static Mgr getMgr() {
if(mgr==null) {
synchronized (Mgr.class) { //一重锁
if(mgr==null) {
synchronized (Mgr.class) { //二重锁
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
mgr = new Mgr();
}
}
}
return mgr;
}
else return mgr;
}
public static void main(String[] args) {
//多线程创建单例对象
for(int i=1; i<100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
Mgr mgr = Mgr.getMgr();
System.out.println(mgr);
}
}).start();}
}
}
这种方法不会产生垃圾对象,也不会产生线程安全。
JVM保证:静态类只被加载一次。而且加载外部类的时候不会加载内部类。
public class Mgr {
private Mgr() {
}
private static class MgrHolder {
private static final Mgr mgr = new Mgr();
}
//判断mgr是否为空
public static Mgr getMgr() {
return MgrHolder.mgr;
}
public static void main(String[] args) {
Mgr mgr = Mgr.getMgr();
}
}
可以防止反序列化
public enum Mgr{
mgr;
}