服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - Java 实例解析单例模式

Java 实例解析单例模式

2022-03-08 00:37FranzLiszt1847 Java教程

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式,这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建

单例模式的介绍

单例对象(Singleton)是一种常用的设计模式。在实际使用中,单例对象能保证在一个JVM中,该对象只存在一个实例存在。

优点

1、减少系统开销,提高系统性能
2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力
3、避免对共享资源的多重占用

缺点

1、不适应用多变的对象
2、扩展困难
3、单例类的职责过重,在一定程度上违背了“单一职责原则”。

Synchronized

Synchronized示例

介绍单例模式前,我们现介绍一下Synchronized
示例如下:
建立一个内部类,并开启子线程,如果实例该类,则自动执行test1()方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class SynchronizedTest implements Runnable {
    private int count;
 
    public SynchronizedTest() {
        count = 0;
    }
 
    @Override
    public void run() {
        test1();
    }
 
    private void test1() {
        synchronized (this) {
            for (int i = 0; i < 5; i++) {
                try {
                    System.out.println(Thread.currentThread().getName() + ":" + count++);
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

构造一个SynchronizedTest 对象,传入两个线程对象

?
1
2
3
4
5
SynchronizedTest test = new SynchronizedTest();
       Thread thread1 = new Thread(test,"test1");
       Thread thread2 = new Thread(test,"test2");
       thread1.start();
       thread2.start();

由结果可知,当一个对象持有该代码块时,另一个线程访问不到被锁住的代码块,只要当前一线程执行完成,另一线程才能执行。

test1:0
test1:1
test1:2
test1:3
test1:4
test2:5
test2:6
test2:7
test2:8
test2:9

Synchronized与非Synchronized

建立一个内部类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class SynchronizedTest implements Runnable {
   private int count;
 
   public SynchronizedTest() {
       count = 0;
   }
 
   @Override
   public void run() {
       if (Thread.currentThread().getName().equals("S")) {
           test1();
       } else {
           test2();
       }
   }
 
   public void test1() {
       synchronized (this) {
           for (int i = 0; i < 5; i++) {
               try {
                   System.out.println(Thread.currentThread().getName() + ":" + (count++));
                   Thread.sleep(500);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
       }
   }
 
   public void test2() {
       for (int i = 0; i < 5; i++) {
           try {
               System.out.println(Thread.currentThread().getName() + ":" + count);
               Thread.sleep(500);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       }
   }
}
?
1
2
3
4
5
SynchronizedTest test = new SynchronizedTest();
        Thread thread1 = new Thread(test,"S");
        Thread thread2 = new Thread(test,"N");
        thread1.start();
        thread2.start();

由结果可知,一个线程访问Synchronized修饰的代码块,另一个线程访问非Synchronized代码块不受阻塞

S:0
N:1
N:2
S:1
N:2
S:2
S:3
N:4
S:4
N:5

Singleton

第一个示例

此示例实现了单例,但是如果放在多线程当中,将会漏洞百出
我们接着看下一个改良示例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton {
/* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */
private static Singleton instance = null;
    /* 私有构造方法,防止被实例化 */
    private Singleton() {
    }
    /* 静态工程方法,创建实例 */
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

第二个示例

根据第一个示例,我们进行改良,加上Synchronized。
但是每次调用getInstance()方法时,都会对对象上锁,为了减少系统开销,我们一般在第一次创建对象的时候加锁,后面就不需要了
我们接着看下一个改良示例

?
1
2
3
4
5
6
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}

第三个示例

我们对上一个示例进行改良,只有在instance == null的时候,也就是第一次创建对象的时候,执行加锁的区域。此种写法解决了上一个示例遗留的问题,但是在Java指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton();语句是分两步执行的。但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间,然后直接赋值给instance成员,然后再去初始化这个Singleton实例。

?
1
2
3
4
5
6
7
8
9
10
public static Singleton getInstance() {
if (instance == null) {
synchronized (instance) {
if (instance == null) {
instance = new Singleton();
      }
   }
 }
 return instance;
}

第四个示例

此代码初看已经没有问题,如果在构造方法中出现异常,那么实例将得不到创建

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Singleton {
/* 私有构造方法,防止被实例化 */
private Singleton() {
}
/* 此处使用一个内部类来维护单例 */
private static class SingletonFactory {
private static Singleton instance = new Singleton();
  }
/* 获取实例 */
public static Singleton getInstance() {
return SingletonFactory.instance;
  }
}

第五个示例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private static Singleton instance = null;
private Singleton(){
 
 }
 public static Singleton getInstance(){
     if (instance == null){
         sync();
     }
     return instance;
 }
private static synchronized void sync(){
     if (instance == null){
        instance = new Singleton();
         System.out.println("success");
    }
 }

到此这篇关于Java 实例解析单例模式的文章就介绍到这了,更多相关Java 单例模式内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/News53231323/article/details/121034929

延伸 · 阅读

精彩推荐
  • Java教程详细了解java监听器和过滤器

    详细了解java监听器和过滤器

    下面小编就为大家带来一篇基于java servlet过滤器和监听器(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    程序dunk10942021-10-03
  • Java教程Spring @Transaction 注解执行事务的流程

    Spring @Transaction 注解执行事务的流程

    这篇文章主要介绍了Spring @Transaction 注解执行事务的流程,Spring 是如何开启事务的?又是如何进行提交事务和关闭事务的,本文给大家详细介绍,需要的朋友...

    程序员小航9112021-09-14
  • Java教程spring cloud中启动Eureka Server的方法

    spring cloud中启动Eureka Server的方法

    本篇文章主要介绍了spring cloud中启动Eureka Server的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    牛奋lch8252021-03-22
  • Java教程Mybatis-Plus 通用CRUD的详细操作

    Mybatis-Plus 通用CRUD的详细操作

    这篇文章主要介绍了Mybatis-Plus 通用CRUD的详细操作,包括插入操作,更新操作及删除操作等,针对每种操作通过实例代码给大家介绍的非常详细,需要的朋友...

    律二萌萌哒11062022-01-05
  • Java教程Java正则之贪婪匹配、惰性匹配

    Java正则之贪婪匹配、惰性匹配

    这篇文章主要介绍了Java正则之贪婪匹配、惰性匹配的相关资料,需要的朋友可以参考下 ...

    hebedich4222019-12-13
  • Java教程Springboot配置suffix指定mvc视图的后缀方法

    Springboot配置suffix指定mvc视图的后缀方法

    这篇文章主要介绍了Springboot配置suffix指定mvc视图的后缀方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...

    绿头龙12652021-09-25
  • Java教程java生成缩略图的方法示例

    java生成缩略图的方法示例

    这篇文章主要介绍了java生成缩略图的方法,结合具体实例形式分析了java生成缩略图过程中所涉及的各种常见的图形处理技巧,需要的朋友可以参考下...

    ITshu2072020-09-01
  • Java教程教你如何监控 Java 线程池运行状态的操作(必看)

    教你如何监控 Java 线程池运行状态的操作(必看)

    这篇文章主要介绍了教你如何监控 Java 线程池运行状态的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    Java技术栈15052021-08-16