单例模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
1,单例类只能有一个实例。
2,单例类必须自己创建自己的唯一实例。
3,单例类必须给所有其他对象提供这一实例。
代码实现
01-恶汉式-构造器私有
/**
* @Author huyouting
* @Date 2021/2/20 14:07
* @Description:
*/
/**
* 饿汗式
* 类加载到内存后,就实例化一个单例,jvm保证线程安全
* 简单实用,推荐使用
* 唯一缺点:不管用到与否,类装载时就完成实例化
*/
public class Mgr01 {
private static final Mgr01 INSTANCE = new Mgr01();
//构造器私有
private Mgr01() {
}
public static Mgr01 getInstance() {
return INSTANCE;
}
public void m() {
System.out.println("m");
}
public static void main(String[] args) {
Mgr01 m1 = Mgr01.getInstance();
Mgr01 m2 = Mgr01.getInstance();
System.out.println(m1 == m2);
}
}
02-恶汉式-静态代码块
/**
* 跟01一个意思
*/
public class Mgr02 {
private static final Mgr02 INSTANCE;
static {
INSTANCE = new Mgr02();
}
//构造器私有
private Mgr02() {
}
public static Mgr02 getInstance() {
return INSTANCE;
}
public void m() {
System.out.println("m");
}
public static void main(String[] args) {
Mgr01 m1 = Mgr01.getInstance();
Mgr01 m2 = Mgr01.getInstance();
System.out.println(m1 == m2);
}
}
03-懒汉式-线程不安全
/**
* lazy loading
* 也称懒汉式
* 虽然达到了按需初始化的目的,但却带来了线程不安全问题
*/
public class Mgr03 {
private static Mgr03 INSTANCE;
//构造器私有
private Mgr03() {
}
public static Mgr03 getInstance() {
if (INSTANCE == null) {
try {
Thread.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Mgr03();
}
return INSTANCE;
}
public void m(){
System.out.println("m");
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
System.out.println(Mgr03.getInstance().hashCode());
}).start();
}
}
}
04-懒汉式-加锁
/**
* @Author huyouting
* @Date 2021/2/20 14:16
* @Description:
*/
/**
* lazy loading
* 也称懒汉式
* 虽然达到了按需初始化的目的,但却带来了线程不安全问题
* 可以枷锁synchronized,但效率下降
*/
public class Mgr04 {
private static Mgr04 INSTANCE;
//构造器私有
private Mgr04() {
}
public static synchronized Mgr04 getInstance() {
if (INSTANCE == null) {
try {
Thread.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Mgr04();
}
return INSTANCE;
}
public void m() {
System.out.println("m");
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
System.out.println(Mgr04.getInstance().hashCode());
}).start();
}
}
}
05-懒汉式-缩小同步代码块范围
/**
* @Author huyouting
* @Date 2021/2/20 14:16
* @Description:
*/
public class Mgr05 {
//禁止指令重排,否则会在没有初始化的情况下返回INSTANCE
private static volatile Mgr05 INSTANCE;
//构造器私有
private Mgr05() {
}
public static Mgr05 getInstance() {
if (INSTANCE == null) {
//试图通过减小同步代码块的方式提高效率,然后不可行
synchronized (Mgr05.class){
try {
Thread.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Mgr05();
}
}
return INSTANCE;
}
public void m() {
System.out.println("m");
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
System.out.println(Mgr05.getInstance().hashCode());
}).start();
}
}
}
06-懒汉式-双重检测锁
/**
* @Author huyouting
* @Date 2021/2/20 14:16
* @Description:
*/
public class Mgr06 {
private static volatile Mgr06 INSTANCE;
//构造器私有
private Mgr06() {
}
public static Mgr06 getInstance() {
if (INSTANCE == null) {
synchronized (Mgr06.class){
//双重检测
if (INSTANCE==null){
try {
Thread.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Mgr06();
}
}
}
return INSTANCE;
}
public void m() {
System.out.println("m");
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
System.out.println(Mgr06.getInstance().hashCode());
}).start();
}
}
}
07-静态内部类方式
/**
* @Author huyouting
* @Date 2021/2/20 14:16
* @Description:
*/
/**
* 静态内部类方式
* JVM保证单例
* 加载外部类时不会加载内部类,这样可以实现懒加载
*/
public class Mgr07 {
private Mgr07(){
}
private static class Mgr07Holder{
private final static Mgr07 INSTANCE = new Mgr07();
}
public static Mgr07 getInstance(){
return Mgr07Holder.INSTANCE;
}
public void m(){
System.out.println("m");
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
System.out.println(Mgr07.getInstance().hashCode());
}).start();
}
}
}
08-枚举
/**
* 不仅可以解决线程同步,还可以防止反序列化
*/
public enum Mgr08 {
INSTANCE;
public void m() {
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
System.out.println(Mgr08.INSTANCE.hashCode());
}).start();
}
}
}