单例模式的定义:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
单例模式的主要作用是确保一个类只有一个实例存在。单例模式可以用在建立目录、数据库连接等需要单线操作的场合,用于实现对系统资源的控制。
单例模式通常有2种表现形式:
(1)饿汉式单例类:类加载时,就进行对象实例化。
(2)懒汉式单例类:第一次引用类时,才进行对象实例化。
饿汉单例类的源代码:
/*
* 饿汉式单例类的源代码
*/
public class Singleton {
private static Singleton instance = new Singleton();
//构造方法私有,保证外界无法直接实例化
private Singleton(){}
//通过该方法获得实例对象
public static Singleton getInstance(){
return instance;
}
}
在类被加载时,静态变量instance会被初始化,此时类的私有构造器会被调用,单例类的唯一实例就被创建了。单例类最重要的特点是类的构造器是私有的,从而避免外界利用构造函数直接创建出任意多的实例。由于构造器是私有的,因此该类不能被继承。
懒汉式单例类的源代码:
public class Singleton1 {
private static Singleton1 instance = null;
//构造方法私有,保证外界无法直接实例化
private Singleton1(){}
//方法同步
synchronized public static Singleton1 getInstance(){
if(instance==null){
instance = new Singleton1();
}
return instance;
}
}
懒汉模式单例类对静态方法getInstance()进行同步,以确保多线程环境下只创建一个实例。
在Spring框架中,每个Bean默认就是单例的。
单例模式的应用实例
以记录王小华手快递次数为例。
/*
* 以收快递为例,演示单例模式的应用
* 饿汉式单例类
*/
public class Person {
private static Person person = new Person();
//取快递次数
private int num = 0;
//构造函数私有化
private Person(){}
//通过哦该方法获得实例对象
public static Person getInstance(){
return person;
}
//返回取快递的次数,并且使用synchronized对该方法进行线程同步
public synchronized String getAnswer(){
return "我是王小华,请稍等马上来!这是第"+ (++num) + "个快递";
}
}
package singletonModel.example;
import java.util.Random;
public class PersonTest {
public static void main(String[] args) {
CourierThread courier1 = new CourierThread("线程1");
CourierThread courier2 = new CourierThread("线程2");
courier1.start();
courier2.start();
}
}
//线程类
class CourierThread extends Thread{
String[] couriers = {"顺丰快递","申通快递","圆通快递","韵达快递","天天快递"};
String threadName = null;
public CourierThread(String name) {
this.threadName = name;
}
@Override
public void run(){
Person person = Person.getInstance(); //创建单例类实例
Random random = new Random();
for(int i = 0; i < couriers.length; i++){
System.out.println(threadName+":你好,我是【"+couriers[random.nextInt(couriers.length)]+"】 请问你是王小华吗?有你的快递,请来取快递!");
System.out.println("回答"+threadName+":\t"+person.getAnswer());
try{
CourierThread.sleep(1000);
}catch(Exception e){
System.out.println(e.getMessage());
}
}
}
}
运行结果
线程1:你好,我是【天天快递】 请问你是王小华吗?有你的快递,请来取快递!
回答线程1: 我是王小华,请稍等马上来!这是第1个快递
线程2:你好,我是【韵达快递】 请问你是王小华吗?有你的快递,请来取快递!
回答线程2: 我是王小华,请稍等马上来!这是第2个快递
线程1:你好,我是【顺丰快递】 请问你是王小华吗?有你的快递,请来取快递!
回答线程1: 我是王小华,请稍等马上来!这是第3个快递
线程2:你好,我是【天天快递】 请问你是王小华吗?有你的快递,请来取快递!
回答线程2: 我是王小华,请稍等马上来!这是第4个快递
线程2:你好,我是【顺丰快递】 请问你是王小华吗?有你的快递,请来取快递!
线程1:你好,我是【韵达快递】 请问你是王小华吗?有你的快递,请来取快递!
回答线程1: 我是王小华,请稍等马上来!这是第5个快递
回答线程2: 我是王小华,请稍等马上来!这是第6个快递
线程1:你好,我是【天天快递】 请问你是王小华吗?有你的快递,请来取快递!
线程2:你好,我是【申通快递】 请问你是王小华吗?有你的快递,请来取快递!
回答线程2: 我是王小华,请稍等马上来!这是第7个快递
回答线程1: 我是王小华,请稍等马上来!这是第8个快递
线程2:你好,我是【顺丰快递】 请问你是王小华吗?有你的快递,请来取快递!
线程1:你好,我是【申通快递】 请问你是王小华吗?有你的快递,请来取快递!
回答线程2: 我是王小华,请稍等马上来!这是第9个快递
回答线程1: 我是王小华,请稍等马上来!这是第10个快递