首页 > 代码库 > 浅析java单例模式
浅析java单例模式
单例模式:运行期间有且仅有一个实例
一. 关键点:
1.一个类只有一个实例------最基本的-----(只提供私有构造器)
2.该类必须自行创建这个实例-----(定义了静态的该类的私有对象)
3.该类必须自行向整个系统提供这个实例---(提供一个静态的公有方法,返回创建或者获取本身的静 态私有对象)
二.基本单例模式
1.懒汉模式
懒汉模式:在类加载的时候,不创建实例,运行调用的时候创建(以时间换空间)
优缺点:类加载快,在运行时获取速度慢;线程不安全;
解决懒汉模式线程安全方法:(1)方法体加同步(2)双重校验锁
懒汉模式特性:lazy Loading(延迟加载)
2.饿汉模式
饿汉模式:在类加载的时候就会完成初始化。(以空间换时间)
优缺点:类加载慢,但在运行时获取对象速度快;线程安全
三.代码展示
懒汉模式代码:
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* 读取数据库配置文件的工具类--单例模式
* */
public class ConfigManager {
// 01定义静态私有本类对象
private static ConfigManager configManager;
private static Properties properties;
// 02私有化本类构造方法--读取配置文件
private ConfigManager() {
// 定义要读取的配置文件
String configFile = "database.properties";
properties = new Properties();
// 以输入流的形式获取配置文件
/**
* ConfigManager.class.getClassLoader():获取本类根目录
* getResourceAsStream(configFile):以流的形式获取配置文件
* */
InputStream is = ConfigManager.class.getClassLoader()
.getResourceAsStream(configFile);
try {
// 读取配置文件(把流放入properties对象)
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 关闭流
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//03 提供全局访问接口
/**
* 懒汉模式:线程不安全,在多线程并发情况下,
* 可能会创建多个ConfigManager实例
*
*
* 001简单懒汉模式--适合单线程安全
* public static ConfigManager getInstance() {
if (configManager == null) {
configManager = new ConfigManager();
}
return configManager;
}
* 解决线程安全问题:
//002.方法体加同步,每一个时间点只允许一个线程通过该方法
public static synchronized ConfigManager getInstance() {
if (configManager == null) {
configManager = new ConfigManager();
}
return configManager;
}
// 04获得properties对象的值
public String getString (String key) {
return properties.getProperty(key);
}
饿汉模式代码
1 import java.io.IOException; 2 import java.io.InputStream; 3 import java.util.Properties; 4 5 /** 6 * 读取数据库配置文件的工具类--单例模式 7 * */ 8 public class ConfigManager { 9 // 01定义静态私有本类对象10 private static ConfigManager configManager=new ConfigManager();//初始化实例 private static Properties properties;15 // 02私有化本类构造方法--读取配置文件16 private ConfigManager() { 17 // 定义要读取的配置文件18 String configFile = "database.properties";19 properties = new Properties();20 // 以输入流的形式获取配置文件21 /**22 * ConfigManager.class.getClassLoader():获取本类根目录23 * getResourceAsStream(configFile):以流的形式获取配置文件24 * */25 InputStream is = ConfigManager.class.getClassLoader()26 .getResourceAsStream(configFile);27 try {28 // 读取配置文件(把流放入properties对象)29 properties.load(is);30 } catch (IOException e) {31 e.printStackTrace();32 } finally {33 try {34 // 关闭流35 is.close();36 } catch (IOException e) {37 e.printStackTrace();38 }39 }40 }41 //03 提供全局访问接口42 69 /*饿汉模式70 * 线程安全:在加载类时创建实例,因为实例是static,71 *所以只加载一次72 * */73 74 public static ConfigManager getInstance(){75 return configManager;76 }77 78 79 // 04获得properties对象的值80 public String getString (String key) {81 return properties.getProperty(key);82 }83 }
*********************注解*********************
/**
* 单例模式讲解类 讲解各种单例模式用法
*
* */
public class SingleTon {
// 饿汉模式变种:静态代码块
private static SingleTon singleTon = null;
static {
//类加载是执行静态代码块,只执行一次
singleTon = new SingleTon();
}
private SingleTon() { }
public static SingleTon getInstance() {
return singleTon;
}
}
**************************************************
// 懒汉模式线程安全之双重校验锁
private static SingleTon singleTon;
private SingleTon() {
}
public static SingleTon getInstance() {
if (singleTon == null) {//第一重校验(第一批并发线程以后的线程不会通过这里,因为已经实例化)
synchronized (SingleTon.class) {//锁,类同步安全(只允许一批并发线程中的一个线程通过)
if (singleTon == null) {//第二重校验(非空判断,实例为空通过,不为空止步)
singleTon = new SingleTon();//校验全部通过,创建实例
}
}
}
return singleTon;
}
}
测试模拟多线程并发与双重锁
package cn.bdqn.util;
/**
* 线程类
* 模拟多线程并发
* */
public class ThreadDemo extends Thread {
private String threadNo;
public ThreadDemo() {
}
public ThreadDemo(String threadNo) {
this.threadNo = threadNo;
}
public String getThreadNo() {
return threadNo;
}
public void setThreadNo(String threadNo) {
this.threadNo = threadNo;
}
@Override
public void run() {
super.run();
//调用单利模式方法,模拟测试双重锁
System.out.println(threadNo);
SingleTon.getInstance(threadNo);
}
}
package cn.bdqn.util;
/*
* 测试类,测试线程双重锁
*
* */
public class ThreadTest {
public static void main(String[] args) {
for (int i = 0; i < 7; i++) {// 相当于主线程,获取资源之后,瞬间生成n个子线程,相当于并发
new ThreadDemo("线程" + i).start();// 创建子线程,并开启
if (i == 3) {
try {
Thread.sleep(1000);//模拟多批线程先后并发
System.out.println("sleep*********");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
执行结果:
*****************************************************
/**
* 静态内部类:解决饿汉模式实现lazy loading(延迟加载)
*
* */
//创建静态变量
private static SingleTon singleTon;
//私有构造
private SingleTon(){}
//静态内部类
private static class SingleTonHelp{
//创建静态常量,完成实例化
private static final SingleTon INSTANCE=new SingleTon();
}
//提供全局访问的接口
public static SingleTon getInstance(){
return SingleTonHelp.INSTANCE;
}
//测试方法
public static void test(){
System.out.println("test==============="+singleTon.toString());
}
package cn.bdqn.util;
/**
* 测试静态内部类
*
* */
public class Test02 {
public static void main(String[] args) {
System.out.println("SingleTon.getInstance()======="+SingleTon.getInstance().toString());
//此时test()报空指针异常,因为没有调用静态类方法,没有加载实例,达到延迟加载效果(即在需要时加载创建实例,不会加载类时加载实例)
SingleTon.test();
}
}
*****************************************************
什么时候使用单利模式:在比较耗系统性能的时候,比如i/o操作,读取配置文件
懒汉模式特性:lazy Loading(延迟加载)
懒汉模式:以时间换空间
饿汉模式:以空间换时间(标准饿汉模式为常用模式,不存在线程安全问题)
浅析java单例模式