定义:
1:单例模式(Singleton Pattern)是指确保一个类在任何情况下都绝只有一个实例,并提供一个全局访问点。
2:隐藏其所有的构造方法:
3:属于创建型模式
在实际业务应用中,Java中的单例模式可以应用于以下场景:
- 资源池管理:在需要对资源进行集中管理的场景下,比如
连接池、线程池、对象池
等,可以使用单例模式来确保资源的唯一性和统一管理。这样可以提高资源的利用效率,避免资源泄露和浪费。- 全局配置管理:当应用程序有全局配置信息需要被共享和使用时,可以使用单例模式来管理这些配置信息。比如
系统属性配置、数据库连接配置、缓存配置等
,通过单例模式可以保证全局的配置信息只有一个实例,方便访问和修改。- 日志记录器:在应用程序中需要
记录日志
信息时,可以使用单例模式来管理日志记录器。这样可以确保日志记录的一致性和唯一性,避免多个日志记录器同时记录导致信息混乱。- 计数器和统计信息:在需要对某个业务操作的
计数或统计信息
进行管理时,可以使用单例模式。比如网站访问量统计、订单数量计数等,通过单例模式可以保证计数器或统计信息的一致性和准确性。框架中常见的单例 ServletContext、ServletConfig、ApplicationContext.........
需要注意的是,单例模式应用于业务场景时需要谨慎,避免过度使用导致代码的复杂性和耦合度增加。在使用单例模式时,应根据具体业务需求进行评估,确保单例模式的适用性和合理性。
package com.tansun.goods.pack;
/**
* 优点:执行效率高,性能高,没有任何的锁
* 缺点:某些情况下,可能会造成内存浪费
* @author Administrator
*/
public class HungrySingleton {
private static final HungrySingleton hungrySingleton = new HungrySingleton();
private HungrySingleton() {
}
public static HungrySingleton getInstance() {
return hungrySingleton;
}
}
package com.tansun.goods.pack;
/**
* @author Administrator
* 优点:节省内存
* 缺点:线程不安全
*/
public class LazySingleton {
private static LazySingleton lazySingleton = null;
private LazySingleton(){
}
public static LazySingleton getInstance(){
if (lazySingleton == null){
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
package com.tansun.goods.pack;
import lombok.extern.slf4j.Slf4j;
/**
* @author Administrator
*/
@Slf4j
public class ExecutorThread implements Runnable{
@Override
public void run() {
LazySingleton instance = LazySingleton.getInstance();
log.debug("The thread name is : {}, hashcode is {}" ,Thread.currentThread().getName(),instance.hashCode());
}
}
package com.tansun.goods.pack;
/**
* @author Administrator
*/
public class LazySingletonTest {
public static void main(String[] args) {
new Thread(new ExecutorThread()).start();
new Thread(new ExecutorThread()).start();
}
}
已连接到目标 VM, 地址: ''127.0.0.1:60386',传输: '套接字''
18:36:55.323 [Thread-0] DEBUG com.tansun.goods.pack.ExecutorThread - The thread name is : Thread-0, hashcode is 1995014693
18:36:55.323 [Thread-1] DEBUG com.tansun.goods.pack.ExecutorThread - The thread name is : Thread-1, hashcode is 597340363
与目标 VM 断开连接, 地址为: ''127.0.0.1:60386',传输: '套接字''
进程已结束,退出代码0
synchronized
package com.tansun.goods.pack;
/**
* @author Administrator
* 优点:节省内存,线程也安全了
* 缺点:性能瓶颈,需要等待
*/
public class LazySingleton {
private static LazySingleton lazySingleton = null;
private LazySingleton(){
}
public static synchronized LazySingleton getInstance(){
if (lazySingleton == null){
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
已连接到目标 VM, 地址: ''127.0.0.1:60540',传输: '套接字''
18:43:31.807 [Thread-0] DEBUG com.tansun.goods.pack.ExecutorThread - The thread name is : Thread-0, hashcode is 761088712
18:43:31.807 [Thread-1] DEBUG com.tansun.goods.pack.ExecutorThread - The thread name is : Thread-1, hashcode is 761088712
与目标 VM 断开连接, 地址为: ''127.0.0.1:60540',传输: '套接字''
进程已结束,退出代码0
通过以上加锁的代码优化解决了出现不同实例的问题,但是新问题随之而来。虽然解决了出现不同实例的现象,随之而来的是性能问题,等待线程队伍太长,性能自然而然下降。
package com.tansun.goods.pack;
/**
* @author Administrator
*/
public class DoubleCheckLazySingleton {
//使用 volatile 关键字修饰的静态变量,确保在多线程环境下的可见性和禁止指令重排序。
private static volatile DoubleCheckLazySingleton doubleCheckLazySingleton = null;
private DoubleCheckLazySingleton() {
//私有构造方法,防止其他类直接实例化对象
}
public static synchronized DoubleCheckLazySingleton getInstance() {
//第一次检查,避免不必要的同步
if (doubleCheckLazySingleton == null) {
//加锁,确保只有一个线程进入同步块
synchronized (DoubleCheckLazySingleton.class) {
//第二次检查,确保只有一个线程创建实例
if (doubleCheckLazySingleton == null) {
//创建实例
doubleCheckLazySingleton = new DoubleCheckLazySingleton();
}
}
}
return doubleCheckLazySingleton;
}
}
已连接到目标 VM, 地址