您的位置:首页 > 编程语言 > Java开发

spring中的单例与java中的单例

2015-12-31 16:27 465 查看

一、概述:

1、spring单例通过设置属性scope="Singleton"完成(默认),其概念和java中的单例概念一致,如在web应用中,每次请求使用的是同一个实例对象。但spring的单例仅限制在其上下文环境中,并没有限制你通过其他方式去创建此对象的其他实例。说白了是spring帮你完成模拟的单例创建,使用。

2、Spring中的单例和设计模式中的单例思想是一样的,不过它不需要编程来实现单例,而是由容器来配置是否单例。即消除了程序性单例

二、传统的单例模式的实现方式

1. 最原始的实现单例模式的方法(存在线程不安全):

public class SingletonOne {

private static SingletonOne instance = null;

private SingletonOne() {}

public static SingletonOne getInstance() {

if (instance == null) {

instance = new SingletonOne();

}

return instance;

}

}

但是这种方法有一个弊端,就是存在线程的不安全!

  比如当两个线程同时进入if(instance == null)时,一个线程判断了当前为空,然后切换到另一个线程,这个线程也判断为空。然后切换回第一个线程,进行实例化,再切换到第二个线程,进行实例化。这样就存在了两个实例。

2. 通过关键字Synchronized强制线程同步

package com.something.singleton;

public class SingletonTwo {

private static SingletonTwo instance = null;

private SingletonTwo() {}

public static synchronized SingletonTwo getInstance() {

if (instance == null) {

instance = new SingletonTwo();

}

return instance;

}

}

这样当线程进行到getInstance会同步的进行,不会有线程安全问题,但是不仅仅是实例化,每次调用也需要同步,这样就会造成很多资源的浪费。

3. 通过静态内部类进行单例

public class SingletonThree {

private static class SingletonHolder{

static SingletonThree instance = new SingletonThree();

}

  private SingletonThree() {}

public static SingletonThree getInstance() {

return SingletonHolder.instance;

}

}

这种方法是最推荐的一种方法,由于Java的调用机制,SingletonHolder只有在调用getInstance的时候才会加载,而内部的静态类只会被加载一次,因此又是线程安全的。

总结起来:

  第一种方法,是存在线程安全问题的。

  第二种方法,则消耗了一定的资源。

  第三种方法,比较推荐。

三、下面通过spring的factory-method来创建单例的bean

1.applicationContext.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd" default-lazy-init="false">

<bean id="Test_pojo" class="cn.wy.test_singleton.Test_pojo">

<property name="age" value="10" />

<property name="name" value="xiaoming" />

<property name="height" value="30" />

</bean>

<bean id="SingletonThree" class="cn.wy.test_singleton.SingletonThree" factory-method="getInstance">

<property name="name" value="wy_test" />

<property name="pojo" ref="Test_pojo" />

</bean>

</beans>

2.Test_pojo类如下:

package cn.wy.test_singleton;

/**

* @Description: TODO

* @author wangy

* @date 2015年12月31日 下午3:52:50

*/

public class Test_pojo {

private int age = 0;

private String name = "unkown";

private int height = 0;

public int getAge() {

return age;

}

public String getName() {

return name;

}

public int getHeight() {

return height;

}

public void setAge(int age) {

this.age = age;

}

public void setName(String name) {

this.name = name;

}

public void setHeight(int height) {

this.height = height;

}

}

3.Singleton类如下:

package cn.wy.test_singleton;

/**

* @Description: 单例模式3

* @author wangy

* @date 2015年12月31日 下午3:39:45

*/

public class SingletonThree {

private Test_pojo pojo = new Test_pojo();

private String name = "unkown";

private SingletonThree() {}

private static class SingletonHolder{

static SingletonThree instance = new SingletonThree();

}

public static SingletonThree getInstance() {

return SingletonHolder.instance;

}

public Test_pojo getPojo() {

return pojo;

}

public void setPojo(Test_pojo pojo) {

this.pojo = pojo;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

}

4.测试类:

package cn.wy.task_schedule;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.wy.test_singleton.SingletonThree;

public class Application {

public static void main(String[] args) {

String[] path= new String[] {

"classpath*:applicationContext-testSingleton.xml"

};

try {

ApplicationContext context = new ClassPathXmlApplicationContext(path);

SingletonThree singleton1 = SingletonThree.getInstance();

SingletonThree singleton2 = (SingletonThree) context.getBean("SingletonThree");

System.out.println("o1'code: " + singleton1.hashCode() + ", o2's code:" + singleton2.hashCode());

System.out.println("starting");

} catch (Exception e) {

// TODO: handle exception

}

}

}

解释:在配置文件中定义"SingletonThree"的bean时候,如果有factory-method="getInstance",则上面示例中的singleton1、singleton2是同一个对象,里面的属性均一致;如果没有factory-method="getInstance",则上面示例中的singleton1、singleton2是两个不同的对象,singleton2中的Test_pojo对象是被赋过值之后的对象,而singleton1中的Test_pojo对象是仅有初始值的对象。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: