文档章节

单例和多例

杨肥麻
 杨肥麻
发布于 2017/07/10 23:55
字数 1615
阅读 12
收藏 0

单例:就是只有一个实例。单例模式确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。

多例:对这个bean的每次请求都会创建一个新的bean实例,类似于new。

Spring中,bean可以被定义为两种模式:prototype(多例)和singleton(单例)Spring bean 默认是单例模式。

1.何时用单例?何时用多例?

struts是基于类的属性进行发的,定义属性可以整个类通用,所以默认是多例,不然多线程访问肯定是共用类里面的属性值的,肯定是不安全的。

struts2来说,action必须用多例,因为action本身含有请求参数的值,即可改变的状态;
 STRUTS1来说,action则可用单例,因为请求参数的值是放在actionForm中,而非action中的;

springmvc是基于方法的开发,都是用形参接收值,一个方法结束参数就销毁了,多线程访问都会有一块内存空间产生,里面的参数也是不会共用的,所有springmvc默认使用了单例,所以controller里面不适合在类里面定义属性,只要controller中不定义属性,那么单例完全是安全的。

2.如何产生单例多例?

 单例在spring中是默认的,如果要产生多例,则在配置文件的bean中添加scope="prototype"; 

3.为什么用单例多例:
    之所以用单例,是因为没必要每个请求都新建一个对象,这样子既浪费CPU又浪费内存;
   之所以用多例,是为了防止并发问题;即一个请求改变了对象的状态,此时对象又处理另一个请求,而之前请求对对象状态的改变导致了对象对另一个请求做了错误的处理;
    用单例和多例的标准只有一个:
    当对象含有可改变的状态时(更精确的说就是在实际应用中该状态会改变),则多例,否则单例;

4.ThreadLocal和线程同步机制的比较

ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。 

同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。 

ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。 

概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。

5.Spring使用ThreadLocal解决线程安全问题 

一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态采用ThreadLocal进行处理,让它们也成为线程安全的状态,因为有状态的Bean就可以在多线程中共享了。 

ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。

线程安全问题都是由全局变量及静态变量引起的。  

若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。

1) 常量始终是线程安全的,因为只存在读操作。 

2)每次调用方法前都新建一个实例是线程安全的,因为不会访问共享的资源。

3)局部变量是线程安全的。因为每执行一个方法,都会在独立的空间创建局部变量,它不是共享的资源。局部变量包括方法的参数变量和方法内变量。

有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象  ,可以保存数据,是非线程安全的。在不同方法调用间不保留任何状态。

无状态就是一次操作,不能保存数据。无状态对象(Stateless Bean),就是没有实例变量的对象  .不能保存数据,是不变类,是线程安全的。

有状态对象:

无状态的Bean适合用不变模式,技术就是单例模式,这样可以共享实例,提高性能。有状态的Bean,多线程环境下不安全,那么适合用Prototype原型模式。Prototype: 每次对bean的请求都会创建一个新的bean实例。

Struts2默认的实现是Prototype模式。也就是每个请求都新生成一个Action实例,所以不存在线程安全问题。需要注意的是,如果由Spring管理action的生命周期, scope要配成prototype作用域。

package com.baobaotao.basic;   

public class SequenceNumber {   

//①通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值   

private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){   

public Integer initialValue(){   

return 0;   

}   

};   

//②获取下一个序列值   

public int getNextNum(){   

seqNum.set(seqNum.get()+1);   

return seqNum.get();   

}   

public static void main(String[] args)   

{   

SequenceNumber sn = new SequenceNumber();   

//③ 3个线程共享sn,各自产生序列号   

TestClient t1 = new TestClient(sn);   

TestClient t2 = new TestClient(sn);   

TestClient t3 = new TestClient(sn);   

t1.start();   

t2.start();   

t3.start();   

}   

private static class TestClient extends Thread   

{   

private SequenceNumber sn;   

public TestClient(SequenceNumber sn) {   

this.sn = sn;   

}   

public void run()   

{   

for (int i = 0; i < 3; i++) {//④每个线程打出3个序列值   

System.out.println("thread["+Thread.currentThread().getName()+   

"] sn["+sn.getNextNum()+"]");   

}   

}   

}   

}   

 

本文转载自:http://www.cnblogs.com/doit8791/p/4093808.html

共有 人打赏支持
杨肥麻
粉丝 1
博文 53
码字总数 30289
作品 0
深圳
单例多例需要搞明白两个问题

什么是单例多例; 2. 如何产生单例多例; 3. 为什么要用单例多例 4. 什么时候用单例,什么时候用多例; 1. 什么是单例多例: 所谓单例就是所有的请求都用一个对象来处理,比如我们常用的servi...

Pig-man
2016/04/09
103
0
设计模式C#描述——单例与多例模式

设计模式C#描述——单例与多例模式 作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。 单例模式有以下特点: 单例类只能...

晨曦之光
2012/03/09
58
0
struts2多例springMVC单例

struts2的控制类action是多例的 springMVC的控制器类Controller是单例的 struts2和springMVC区别在于对数据的处理不同,struts2以属性形式绑定数据,因此必须多例才不会数据混乱。 springMV...

LYQ1990
2016/05/24
158
0
spring IOC部分源码解析

一:原理 当bean是单例时,从缓存获取单例bean;如果没有,则创建单例bean,创建单例bean时用反射获取bean的构造器,通过构造器实例化bean,然后在组装bean,组装bean的时候进行依赖注入;之...

cw134876
04/26
0
0
Spring MVC Controller单例陷阱

Spring MVC Controller默认是单例的: 单例的原因有二: 1、为了性能。 2、不需要多例。 1、这个不用废话了,单例不用每次都new,当然快了。 2、不需要实例会让很多人迷惑,因为spring mvc官...

动听的椰子
2016/02/29
94
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring JdbcTemplate模板模式与回调结合分析

在看Spring的JdbcTemplate的时候,看到其将模板模式和回调模式结合使用的实现,可以精妙的解决很多的问题。详见Spring中涉及的设计模式总结中的关于模板模式和回调模式结合的具分析,本文利用...

宸明
30分钟前
0
0
docker update:更新一个或多个容器的配置

更新容器的配置 docker update:更新一个或多个容器的配置。 具体内容请访问:https://docs.docker.com/engine/reference/commandline/update/#options 语法:docker update [OPTIONS] CONTA...

lwenhao
今天
1
0
unload事件

unload事件不触发的原因分析 1.代码位置不对,应该优先加载,不能放到回调函数中 2.浏览器不支持 3.最可能的原因,unload事件中触发的函数是一个异步执行的函数,浏览器是不允许在窗口关闭之后在...

狮子狗
今天
1
0
DbForge Schema Compare for MySQL入门教程:如何连接到数据库

【dbForge Schema Compare for MySQL下载】 要创建连接: 1. 在“Connection” 工具栏上单击“New Connection”按钮 。 2. 在“Host” 框中输入主机名。 3. 在“Port” 框中输入端口信息。默...

Miss_Hello_World
今天
2
0
spring中事务的应用

spring中事务管理的两种方式 编程式事务使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。 声明式事务是建立...

狂奔的熊二
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部