大家好,又见面了,我是你们的朋友全栈君。
根据马士兵老师的视频整理下来的8种单例模式的实现方式,在此记录一下。
代码示例1:饿汉式
代码语言:javascript复制package com.examples.singleton;
public class Mgr01 {
public static void main(String[] args) {
Mgr01 m1 = Mgr01.getInstance();
Mgr01 m2 = Mgr01.getInstance();
System.out.println(m1==m2);
}
//class文件加载时进行类的实例化
private static Mgr01 INSTANCE = new Mgr01();
//构造方法私有化
private Mgr01(){};
public static Mgr01 getInstance(){return INSTANCE;}
public void m(){ System.out.println("Mgr01"); }
}
说明:
以上是饿汉式单例,就是在类加载的时候完成实例化,而且只有一个实例;同时JVM能够保证线程安全,简单实用,推荐使用。
缺点:不管是否用到,类装载的时候就已经完成了实例化
代码示例2:和示例1类似,只不过将实例化在静态代码块中完成
代码语言:javascript复制package com.examples.singleton;
public class Mgr02 {
public static void main(String[] args) {
Mgr02 m1 = Mgr02.getInstance();
Mgr02 m2 = Mgr02.getInstance();
System.out.println(m1==m2);
}
//class文件加载时进行类的实例化
private static Mgr02 INSTANCE ;
static {
INSTANCE = new Mgr02();
}
//构造方法私有化
private Mgr02(){};
public static Mgr02 getInstance(){return INSTANCE;}
public void m(){ System.out.println("Mgr01"); }
}
代码示例3:懒汉式
代码语言:javascript复制package com.examples.singleton;
public class Mgr03 {
public static void main(String[] args) {
for(int i=0;i<50;i ) {
new Thread(()->{
System.out.println(Mgr03.getInstance().hashCode());
}).start();
}
}
private static Mgr03 INSTANCE ;
//构造方法私有化
private Mgr03(){};
public static Mgr03 getInstance(){
if(INSTANCE==null){
try{
Thread.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
INSTANCE = new Mgr03();
}
return INSTANCE;
}
public void m(){ System.out.println("Mgr01"); }
}
多线程执行结果:
说明:为了解决不管是否使用都会实例化的问题,但是却带来线程不安全的问题
代码示例4:懒汉式 锁
代码语言:javascript复制package com.examples.singleton;
public class Mgr03 {
public static void main(String[] args) {
for(int i=0;i<50;i ) {
new Thread(()->{
System.out.println(Mgr03.getInstance().hashCode());
}).start();
}
}
private static Mgr03 INSTANCE ;
//构造方法私有化
private Mgr03(){};
public static synchronized Mgr03 getInstance(){
if(INSTANCE==null){
try{
Thread.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
INSTANCE = new Mgr03();
}
return INSTANCE;
}
public void m(){ System.out.println("Mgr01"); }
}
说明: 通过给getInstance()方法加锁,解决对象不唯一的问题,但是同时也带来效率下降的问题
代码示例5:懒汉式 锁 减少同步代码块
代码语言:javascript复制package com.examples.singleton;
public class Mgr05 {
public static void main(String[] args) {
for(int i=0;i<50;i ) {
new Thread(()->{
System.out.println(Mgr05.getInstance().hashCode());
}).start();
}
}
private static Mgr05 INSTANCE ;
private Mgr05(){};
public static Mgr05 getInstance(){
if(INSTANCE==null){
//试图通过减小同步代码块的方式提高效率,但是并不可行
synchronized(Mgr05.class){
try{
Thread.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
INSTANCE = new Mgr05();
}
}
return INSTANCE;
}
public void m(){ System.out.println("Mgr01"); }
}
多线程执行结果:
说明:同样存在线程不安全的问题,因为第一个if判断条件有可能导致在对象没有实例化之前,不同的线程进入到if代码块中,拿到锁之后进行实例化
代码示例6:懒汉式 锁 双重检查
代码语言:javascript复制package com.examples.singleton;
public class Mgr06 {
public static void main(String[] args) {
for(int i=0;i<50;i ) {
new Thread(()->{
System.out.println(Mgr06.getInstance().hashCode());
}).start();
}
}
private static Mgr06 INSTANCE ;
private Mgr06(){};
public static Mgr06 getInstance(){
if(INSTANCE==null){
//双重检查
synchronized(Mgr06.class){
if(INSTANCE==null) {
try{
Thread.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
INSTANCE = new Mgr06();
}
}
}
return INSTANCE;
}
public void m(){ System.out.println("Mgr01"); }
}
可以保证线程安全
代码示例7:静态内部类
代码语言:javascript复制package com.examples.singleton;
public class Mgr07 {
public static void main(String[] args) {
for(int i=0;i<50;i ) {
new Thread(()->{
System.out.println(Mgr07.getInstance().hashCode());
}).start();
}
}
private static class Mgr07Holder{
private final static Mgr07 INSTANCE = new Mgr07();
}
private Mgr07(){};
public static Mgr07 getInstance(){
return Mgr07Holder.INSTANCE;
}
public void m(){ System.out.println("Mgr01"); }
}
说明:加载外部类时不会加载内部类,这样可以实现懒加载,JVM保证线程安全,类只加载一次
代码示例8:枚举类
代码语言:javascript复制package com.examples.singleton;
public enum Mgr08 {
INSTANCE;
public void m(){ System.out.println("Mgr08"); }
public static void main(String[] args) {
for(int i=0;i<50;i ) {
new Thread(()->{
System.out.println(Mgr08.INSTANCE.hashCode());
}).start();
}
}
}
说明:以上方法不单能实现单例,而且能防止被反序列化,因为枚举类没有构造方法,所以即使得到了class文件也不能被反序列化。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/156766.html原文链接:https://javaforall.cn