重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种。
成都创新互联主营钟祥网站建设的网络公司,主营网站建设方案,app软件开发,钟祥h5微信小程序开发搭建,钟祥网站营销推广欢迎钟祥等地区企业咨询
单例模式有一下特点:
1、单例类只能有一个实例。
2、单例类必须自己自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。
首先看一个经典的单例实现。
public class Singleton {
private static Singleton uniqueInstance = null;
private Singleton() {
// Exists only to defeat instantiation.
}
public static Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// Other methods...
}
Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。(事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效。此问题在此处不做讨论,姑且掩耳盗铃地认为反射机制不存在。)
但是以上实现没有考虑线程安全问题。所谓线程安全是指:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。显然以上实现并不满足线程安全的要求,在并发环境下很可能出现多个Singleton实例。
//////////////////////////////////////////////////////////////////////
验证单例模式的示例
//////////////////////////////////////////////////////////////////////
public class TestStream {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 该类只能有一个实例
private TestStream() {
} // 私有无参构造方法
// 该类必须自行创建
// 有2种方式
private static TestStream ts1 = null;
// 这个类必须自动向整个系统提供这个实例对象
public static TestStream getTest() {
if (ts1 == null) {
ts1 = new TestStream();
}
return ts1;
}
public void getInfo() {
System.out.println("output message " + name);
}
public static void main(String[] args) {
TestStream s = TestStream.getTest();
s.setName("张孝祥 1");
System.out.println(s.getName());
TestStream s1 = TestStream.getTest();
s1.setName("张孝祥 2");
System.out.println(s1.getName());
s.getInfo();
s1.getInfo();
if (s == s1) {
System.out.println("创建的是同一个实例");
} else if (s != s1) {
System.out.println("创建的不是同一个实例");
} else {
System.out.println("application error");
}
}
}
////////////////////////////////////////////
单例模式(Singleton) ,属于最常见的设计模式之一,大部分系统都会用到,目的是为了维护系统中唯一的一个实例。
可分为eager模式,示例代码如下:
Java代码
1.class EagerSingleton{
2. private static final EagerSingleton m_instance = new EagerSingleton();
3. private EagerSingleton(){}
4. public static EagerSingleton getInstance(){
5. return m_instance;
6. }
7.}
class EagerSingleton{
private static final EagerSingleton m_instance = new EagerSingleton();
private EagerSingleton(){}
public static EagerSingleton getInstance(){
return m_instance;
}
}
和 lazy模式,示例代码如下:
Java代码
1.class LazySingleton{
2. private static LazySingleton m_instance = null;
3. private LazySingleton(){}
4. public synchronized static getInstance(){
5. if(m_instance == null){
6. m_instance = new LazySingleton();
7. }
8. return m_instance;
9. }
10.}
class LazySingleton{
private static LazySingleton m_instance = null;
private LazySingleton(){}
public synchronized static getInstance(){
if(m_instance == null){
m_instance = new LazySingleton();
}
return m_instance;
}
}
java源码中,Runtime.getRuntime()就是单例的一个例子。
单例模式的精神就是整个系统中维护一个实例,推广开来,如果在一个系统中需要维护多个示例,那么就产生了多例模式(multiton)。
多例模式(Multiton) ,通过聚集对象了保留自身的多个示例,根据客户端的参数返回所需要的实例。
示例代码如下:
Java代码
1.class Multiton{
2. private final int INSTANCE_SIZE = 10;
3. private static Map instances = new HashMap(INSTANCE_SIZE);
4. private String name;
5. private Multiton(){}
6. private Multiton(String name){
7. this.name = name;
8. }
9. public synchronized static getInstance(String name){
10. if(instances.containsKey(name)){
11. return instances.get(name);
12. }
13. else{
14. ins = new Multiton(name);
15. instances.put(name, ins);
16. return ins;
17. }
18. }
19.}
class Multiton{
private final int INSTANCE_SIZE = 10;
private static Map instances = new HashMap(INSTANCE_SIZE);
private String name;
private Multiton(){}
private Multiton(String name){
this.name = name;
}
public synchronized static getInstance(String name){
if(instances.containsKey(name)){
return instances.get(name);
}
else{
ins = new Multiton(name);
instances.put(name, ins);
return ins;
}
}
}
[nextpage]
一个实用的例子就是KeyGenerator, 示例代码如下:
Java代码
1.class KeyGenerator{
2. private final int POOL_SIZE = 20;
3. private static Map instances = new HashMap(16);
4. private KeyInfo keyinfo;
5. private KeyGenerator(){}
6. private KeyGenerator(String keyName){
7. this.keyinfo = new KeyInfo(POOL_SIZE, keyName);
8. }
9. public synchronized static getInstance(String keyName){
10. if(instances.containsKey(keyName)){
11. return (KeyGenerator)instances.get(keyName);
12. }
13. else{
14. keyGen = new KeyGenerator(keyName);
15. instances.put(name, keyGen);
16. return keyGen;
17. }
18. }
19. public synzhronized int getNextKey(){
20. return keyinfo.getNextKey();
21. }
22. }
class KeyGenerator{
private final int POOL_SIZE = 20;
private static Map instances = new HashMap(16);
private KeyInfo keyinfo;
private KeyGenerator(){}
private KeyGenerator(String keyName){
this.keyinfo = new KeyInfo(POOL_SIZE, keyName);
}
public synchronized static getInstance(String keyName){
if(instances.containsKey(keyName)){
return (KeyGenerator)instances.get(keyName);
}
else{
keyGen = new KeyGenerator(keyName);
instances.put(name, keyGen);
return keyGen;
}
}
public synzhronized int getNextKey(){
return keyinfo.getNextKey();
}
}
创建一个名字为“ReportCard”的类,然后用下边的内容全部替换掉,你会成为全班最亮的仔。
import java.util.HashMap;
/**
* 学生成绩单
*/
public class ReportCard {
public static void main(String[] args) {
ReportCard reportCard = new ReportCard("张三", "070602213");
reportCard.set("语文", 80.0);
reportCard.set("数学", 59.5);
reportCard.set("英语", 66.0);
reportCard.set("java", 80, 99.0);
reportCard.set("数据库", 80, 66.0);
reportCard.set("毛概", null);
System.out.println(reportCard.getStudentName() + "语文分数:" + reportCard.get("语文"));
System.out.println(reportCard.getStudentName() + "数学考核结果:" + (reportCard.isPassed("数学") ? "合格" : "不合格"));
System.out.println(reportCard.getStudentName() + "期末是否挂科:" + (reportCard.isAllPassed() ? "否" : "是"));
}
// 学生姓名
private String studentName;
// 学生学号
private String studentNumber;
// 成绩单
private HashMapString, CourseResult cards = new HashMap();
public ReportCard() {
}
public ReportCard(String studentName, String studentNumber) {
this.studentName = studentName;
this.studentNumber = studentNumber;
}
public Double get(String courseName){
CourseResult courseResult = cards.get(courseName);
return courseResult == null ? Double.NaN : courseResult.getStudentScore();
}
public void set(String courseName, Double studentScore){
CourseResult courseResult = new CourseResult(courseName, studentScore);
cards.put(courseName, courseResult);
}
public void set(String courseName, double passMark, Double studentScore){
CourseResult courseResult = new CourseResult(courseName, passMark, studentScore);
cards.put(courseName, courseResult);
}
public boolean isPassed(String courseName){
return cards.get(courseName).isPassed();
}
public boolean isAllPassed(){
for(CourseResult cr : cards.values()){
if ( ! cr.isPassed()) {
return false;
}
}
return true;
}
public String getStudentName() {
return studentName;
}
public String getStudentNumber() {
return studentNumber;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public void setStudentNumber(String studentNumber) {
this.studentNumber = studentNumber;
}
/**
* 课程
*/
class Course{
// 课程名称
protected String courseName;
// 及格分
protected double passMark = 60;
public Course(String courseName, Double passMark) {
this.courseName = courseName;
if ( passMark != null) {
this.passMark = passMark;
}
}
}
/**
* 课程成绩
*/
class CourseResult extends Course{
// 学生成绩
private Double studentScore;
public CourseResult(String courseName, Double studentScore) {
this(courseName, null, studentScore);
}
public CourseResult(String courseName, Double passMark, Double studentScore) {
super(courseName, passMark);
this.studentScore = studentScore == null ? Double.NaN : studentScore;
}
public boolean isPassed(){
return studentScore = passMark;
}
public String getCourseName() {
return courseName;
}
public double getPassMark() {
return passMark;
}
public Double getStudentScore() {
return studentScore;
}
}
一、懒汉式单例\x0d\x0a在类加载的时候不创建单例实例。只有在第一次请求实例的时候的时候创建,并且只在第一次创建后,以后不再创建该类的实例。\x0d\x0a \x0d\x0apublic class LazySingleton {\x0d\x0a /**\x0d\x0a * 私有静态对象,加载时候不做初始化\x0d\x0a */\x0d\x0a private static LazySingleton m_intance=null;\x0d\x0a /**\x0d\x0a * 私有构造方法,避免外部创建实例\x0d\x0a */\x0d\x0a private LazySingleton(){\x0d\x0a }\x0d\x0a /**\x0d\x0a * 静态工厂方法,返回此类的唯一实例. \x0d\x0a * 当发现实例没有初始化的时候,才初始化.\x0d\x0a */\x0d\x0a synchronized public static LazySingleton getInstance(){\x0d\x0a if(m_intance==null){\x0d\x0a m_intance=new LazySingleton();\x0d\x0a }\x0d\x0a return m_intance;\x0d\x0a }\x0d\x0a}\x0d\x0a\x0d\x0a二、饿汉式单例\x0d\x0a在类被加载的时候,唯一实例已经被创建。\x0d\x0a \x0d\x0apublic class EagerSingleton {\x0d\x0a /**\x0d\x0a * 私有的(private)唯一(static final)实例成员,在类加载的时候就创建好了单例对象\x0d\x0a */\x0d\x0a private static final EagerSingleton m_instance = new EagerSingleton();\x0d\x0a /**\x0d\x0a * 私有构造方法,避免外部创建实例\x0d\x0a */\x0d\x0a private EagerSingleton() {\x0d\x0a }\x0d\x0a /**\x0d\x0a * 静态工厂方法,返回此类的唯一实例.\x0d\x0a * @return EagerSingleton\x0d\x0a */\x0d\x0a public static EagerSingleton getInstance() {\x0d\x0a return m_instance;\x0d\x0a }\x0d\x0a}\x0d\x0a \x0d\x0a************************************************************************************** 懒汉方式,指全局的单例实例在第一次被使用时构建; \x0d\x0a饿汉方式,指全局的单例实例在类装载时构建 \x0d\x0a**************************************************************************************\x0d\x0a\x0d\x0a三、登记式单例\x0d\x0a这个单例实际上维护的是一组单例类的实例,将这些实例存放在一个Map(登记薄)中,对于已经登记过的实例,则从工厂直接返回,对于没有登记的,则先登记,而后返回。\x0d\x0apublic class RegSingleton {\x0d\x0a /**\x0d\x0a * 登记薄,用来存放所有登记的实例\x0d\x0a */\x0d\x0a private static Map m_registry = new HashMap();\x0d\x0a //在类加载的时候添加一个实例到登记薄\x0d\x0a static {\x0d\x0a RegSingleton x = new RegSingleton();\x0d\x0a m_registry.put(x.getClass().getName(), x);\x0d\x0a }\x0d\x0a /**\x0d\x0a * 受保护的默认构造方法\x0d\x0a */\x0d\x0a protected RegSingleton() {\x0d\x0a }\x0d\x0a /**\x0d\x0a * 静态工厂方法,返回指定登记对象的唯一实例;\x0d\x0a * 对于已登记的直接取出返回,对于还未登记的,先登记,然后取出返回\x0d\x0a * @param name\x0d\x0a * @return RegSingleton\x0d\x0a */\x0d\x0a public static RegSingleton getInstance(String name) {\x0d\x0a if (name == null) {\x0d\x0a name = "RegSingleton";\x0d\x0a }\x0d\x0a if (m_registry.get(name) == null) {\x0d\x0a try {\x0d\x0a m_registry.put(name, (RegSingleton) Class.forName(name).newInstance());\x0d\x0a } catch (InstantiationException e) {\x0d\x0a e.printStackTrace();\x0d\x0a } catch (IllegalAccessException e) {\x0d\x0a e.printStackTrace();\x0d\x0a } catch (ClassNotFoundException e) {\x0d\x0a e.printStackTrace();\x0d\x0a }\x0d\x0a }\x0d\x0a return m_registry.get(name);\x0d\x0a }\x0d\x0a /**\x0d\x0a * 一个示意性的商业方法\x0d\x0a * @return String\x0d\x0a */\x0d\x0a public String about() {\x0d\x0a return "Hello,I am RegSingleton!";\x0d\x0a }\x0d\x0a}