Java 实例解析单例模式

网友投稿 241 2022-11-26

Java 实例解析单例模式

目录单例模式的介绍优点缺点SynchronizedSynchronized示例Synchronized与非SynchronizedSingleton第一个示例第二个示例第三个示例第四个示例第五个示例

单例模式的介绍

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

优点

1、减少系统开销,提高系统性能

2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力

3、避免对共享资源的多重占用

缺点

1、不适应用多变的对象

2、扩展困难

3、单例类的职责过重,在一定程度上违背了“单一职责原则”。

Synchronized

Synchronized示例

介绍单例模式前,我们现介绍一下Synchronized

示例如下:

建立一个内部类,并开启子线程,如果实例该类,则自动执行test1()方法

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 对象,传入两个线程对象

SynchronizedTest test = new SynchronizedTest();

Thread thread1 = new Thread(test,"test1");

Thread thread2 = new Thread(test,"test2");

thread1.start();

thread2.start();

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

test1:0

test1:1

test1:2

test1:3

test1:4

test2:5

test2:6

test2:7

test2:8

test2:9

Synchronized与非Synchronized

建立一个内部类

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();

}

}

}

}

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

第一个示例

此示例实现了单例,但是如果放在多线程当中,将会漏洞百出

我们接着看下一个改良示例

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()方法时,都会对对象上锁,为了减少系统开销,我们一般在第一次创建对象的时候加锁,后面就不需要了

我们接着看下一个改良示例

public static synchronized Singleton getInstance() {

if (instance == null) {

instance = new Singleton();

}

return instance;

}

第三个示例

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

public static Singleton getInstance() {

if (instance == null) {

synchronized (instance) {

if (instance == null) {

instance = new Singleton();

}

}

}

return instance;

}

第四个示例

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

public class Singleton {

/* 私有构造方法,防止被实例化 */

private Singleton() {

}

/* 此处使用一个内部类来维护单例 */

private static class SingletonFactory {

private static Singleton instance = new Singleton();

}

/* 获取实例 */

public static Singleton getInstance() {

return SingletonFactory.instance;

}

}

第五个示例

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");

}

}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:串口服务器是实现远程控制、数据采集的必要网络设备
下一篇:Hadoop 之 MapReduce
相关文章

 发表评论

暂时没有评论,来抢沙发吧~