单例模式,顾名思义就是确保一个类只有一个实例。单例模式英文原话“Ensure a class has only one instance,and provide a global point of access to it.”翻译,单例模式是确保一个类只有一个实例,而且自行实例化并向这个系统提供这个实例。单例模式通常分三种:饿汉式单例类、懒汉式单例类和登记式单例类。下面说说前两种单例类。
饿汉式单例类是在类加载时,进行对象实例化;懒汉式单例类是在第一次引用该类时进行对象实例化。
饿汉式单例类代码如下所示:
public class Singleton{
private static Singleton _instance = new Singleton();
//构造方法私有,保证外界不能直接实例化;
private Singleton(){
}
//通过该方法获得实例对象;
public static getInstance(){
return _instance;
}
}
懒汉式单例类代码如下所示:
public class Singleton{
private static Singleton _instance =null;
//构造方法私有,保证外界不能直接实例化;
private Singleton(){
}
//通过该方法获得实例对象,此时应该同步,防止多个线程同时调用该方法而创建多个实例;
public static synchronized getInstance(){
if(_instance==null){
_instance = new Singleton();
}
return _instance
}
}
以上代码片段可以看出饿汉式单例类和懒汉式单例类的差别。需要注意的是,懒汉式单例获得实例的方法需要同步,饿汉式不必同步,因为实例在类加载时已经创建了,即使多个线程同时调用该方法获得还是同个实例;单例类的构造方法都是私有的。下面写一个多线程访问单列类的demo,demo中使用的是饿汉式单例类,其实Java语言更适合使用饿汉式单例类。下面上代码。
单例类如下:
//单例类,该单例类实现一个计数功能;
public class NumController {
private static NumController nController = new NumController();
private int num = 0;
//单例类的构造函数是private的,只供自己调用;
private NumController(){
}
//向调用者提供单例对象;
public static NumController getInstance(){
return nController;
}
//计数器加1,注意要同步;
public synchronized int getNum(){
return num++;
}
}
下面是主函数类:
public class SingletonPatternTest {
/**
* @param args
*/
public static void main(String[] args) {
//创建两个访问单例类的线程,由于线程是用内部类实现,所以需要先创建一个外围对象;
SingletonPatternTest spt = new SingletonPatternTest();
//将单例类对象传递给线程;
Thread threadOne = spt.new ThreadOne(NumController.getInstance());
Thread threadTwo = spt.new ThreadTwo(NumController.getInstance());
//开启线程
threadOne.start();
threadTwo.start();
}
class ThreadOne extends Thread{
NumController nController;
public ThreadOne(){
}
public ThreadOne(NumController nController){
this.nController=nController;
}
public void run(){
for(int i=0;i<5;i++){
System.out.println("这是ThreadOne第"+nController.getNum()+"次访问NumController");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
class ThreadTwo extends Thread{
NumController nController;
public ThreadTwo(){
}
public ThreadTwo(NumController nController){
this.nController=nController;
}
public void run(){
for(int i=0;i<5;i++){
System.out.println("这是ThreadTwo第"+nController.getNum()+"次访问NumController");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
运行结果如下:
这是ThreadOne第0次访问NumController
这是ThreadTwo第1次访问NumController
这是ThreadTwo第2次访问NumController
这是ThreadOne第3次访问NumController
这是ThreadOne第4次访问NumController
这是ThreadTwo第5次访问NumController
这是ThreadOne第6次访问NumController
这是ThreadTwo第7次访问NumController
这是ThreadOne第8次访问NumController
这是ThreadTwo第9次访问NumController