1. 单例模式的定义
单例模式的英文定义:
Ensure a class has only one instance, and provide a global point of access to it.
大体的意思就是确保一个类有且只有一个实例,并且提供一个全局的指针来操作该类。单例模式的主要意思就是确保一个类只有一个实例。单例模式可以用来建立目录、数据库连接等需要单线程操作的场合,用于对系统资源的控制。
由于Java语言的特点,存在两种单例形式:
(1)饿汉式单例类:当Java虚拟机加载该类的时候,就对该类进行实例化;
(2)懒汉式单例类:第一次创建该类的引用的时候,才对该类进行实例化。
饿汉单例类的StarUML类图:
对于此类图而言,首先构造函数私有,外部无法对该类进行实例化,其次包含一个静态的该类的私有的引用和一个返回该引用的公共的静态方法。如此一来饿汉式单例类就创建完成。如下代码为StarUML所生成的代码:
import java.util.*;
/**
*
*/
public class Singleton {
/**
* Default constructor
*/
private Singleton() {//public修改成为private
}
/**
*
*/
private static Singleton instance = new Singleton();
/**
* @return
*/
public static Singleton getInstance() {
// TODO implement here
return instance;//返回instance
}
}
懒汉单例类的StarUML类图:
如下代码为StarUML所生成的代码:
import java.util.*;
/**
*
*/
public class Singleton {
/**
* Default constructor
*/
**private** Singleton() {//public修改成为private
}
/**
*
*/
private static Singleton instance = null;
/**
* @return
*/
public static Singleton getInstance() {
// TODO implement here
if(instance==null){//为保证线程安全采取double check并且加入synchronized保证线程同步
synchronized(Singleton.class){
if(instance==null){
instance = new SIngleton();
}
}
return instance;
}
}
懒汉式单例模式和饿汉式单例模式的区别,饿汉式单例模式在同一个jvm下能保证在创建线程时只创建一个对象,这与jvm模式有关,对于懒汉式单例模式需要使用synchronized关键字保证线程同步。
2.测试单例模式(饿汉式单例模式)
这个例子用来大致模拟大家买票的行为:
Ticket.java
package fengqi.wang;
public class Ticket {
private static Ticket instance = new Ticket();
private int totalTickets = 20;
private Ticket() {
}
public static Ticket getInstance() {
return instance;
}
synchronized public int sell() {// 保证线程同步
if (totalTickets > 0) {
return --totalTickets;
}
return -1;
}
}
TicketCounter.java
package fengqi.wang;
public class TicketCounter implements Runnable {
private String name = "";
public TicketCounter(String name) {
// TODO Auto-generated constructor stub
this.name = name;
}
@Override
public void run() {
// TODO Auto-generated method stub
Ticket t = Ticket.getInstance();
while (true) {
int count = t.sell();
if (count > -1) {
System.out.println(this.name + "卖出了第" + (20 - count) + "票。");
} else {
System.out.println("票已售罄!!!");
break;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
TestTicketCounter.java
package fengqi.wang;
public class TestTicketCounter {
public static void main(String[] args) {
Thread t1 = new Thread(new TicketCounter("窗口1"));
Thread t2 = new Thread(new TicketCounter("窗口2"));
Thread t3 = new Thread(new TicketCounter("窗口3"));
Thread t4 = new Thread(new TicketCounter("窗口4"));
t1.start();
t2.start();
t3.start();
t4.start();
}
}
3.测试结果
窗口2卖出了第2票。
窗口1卖出了第1票。
窗口3卖出了第3票。
窗口4卖出了第4票。
窗口1卖出了第6票。
窗口3卖出了第7票。
窗口2卖出了第5票。
窗口4卖出了第8票。
窗口3卖出了第11票。
窗口4卖出了第12票。
窗口1卖出了第9票。
窗口2卖出了第10票。
窗口1卖出了第13票。
窗口3卖出了第16票。
窗口4卖出了第15票。
窗口2卖出了第14票。
窗口1卖出了第17票。
窗口4卖出了第19票。
窗口3卖出了第18票。
窗口2卖出了第20票。
票已售罄!!!
票已售罄!!!
票已售罄!!!
票已售罄!!!