【设计模式】单例模式 在java中的应用
文章目录
- 引言
- 什么是单例模式
- 单例模式的应用场景
- 单例模式的优缺点
- 优点
- 缺点
- 单例模式的基本实现
- 饿汉式单例模式
- 懒汉式单例模式
- 双重检查锁定
- 静态内部类
- 枚举单例
- 单例模式的线程安全问题
- 多线程环境下的单例模式
- 线程安全的实现方式
- 1. **懒汉式单例模式(线程不安全)**
- 2. **懒汉式单例模式(线程安全,使用同步方法)**
- 3. **双重检查锁定**
- 4. **静态内部类**
- 5. **枚举单例**
- 单例模式的序列化与反序列化
- 序列化导致的问题
- 如何防止反序列化破坏单例
- 单例模式的反射攻击
- 反射攻击导致的问题
- 如何防止反射破坏单例
- 使用枚举类型防止反射和序列化攻击
- 单例模式的实际应用案例
- 数据库连接池管理
- 日志管理
- 配置文件管理
- 总结
- 单例模式的最佳实践
- 单例模式的使用建议
引言
什么是单例模式
单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。单例模式通过控制实例化过程来避免创建多个实例,从而节省资源并确保全局状态的一致性。
在 Java 中,实现单例模式的核心思想是私有化构造方法,并通过一个公共的静态方法来返回类的唯一实例。
单例模式的应用场景
单例模式适用于以下场景:
- 资源管理器:如线程池、数据库连接池等,这些资源通常是重量级的,频繁创建和销毁会带来性能开销,因此需要一个全局唯一的实例来管理这些资源。
- 配置管理:应用程序的配置文件通常是全局唯一的,使用单例模式可以确保配置的唯一性和一致性。
- 日志记录器:日志记录器在整个应用程序中通常是唯一的,使用单例模式可以确保日志记录的统一性和线程安全性。
- 缓存:缓存数据通常需要全局唯一的实例来管理,以便在不同的地方访问和修改缓存时保持一致性。
单例模式的优缺点
优点
- 控制实例数量:确保一个类只有一个实例,避免了实例的重复创建,节省系统资源。
- 全局访问点:提供一个全局访问点,使得访问该实例变得简单。
- 延迟加载:某些实现方式(如懒汉式单例)可以实现延迟加载,即在需要时才创建实例,从而提高系统性能。
缺点
- 不易扩展:由于单例类的构造方法是私有的,继承和扩展变得困难。
- 隐藏依赖关系:单例模式隐藏了类之间的依赖关系,增加了代码的复杂性和维护难度。
- 多线程问题:在多线程环境下实现单例模式时,需要考虑线程安全问题,否则可能会创建多个实例。
单例模式的基本实现
饿汉式单例模式
饿汉式单例模式在类加载时就创建实例,确保类在第一次引用时就已经实例化。
public class HungrySingleton {// 类加载时就创建实例private static final HungrySingleton instance = new `();// 私有构造方法,防止外部实例化private HungrySingleton() {}// 提供公共的静态方法获取实例public static HungrySingleton getInstance() {return instance;}
}
优点:
- 实现简单。
- 线程安全,因为实例在类加载时就创建了。
缺点:
- 如果实例占用资源较多且未被使用,会造成资源浪费。
懒汉式单例模式
懒汉式单例模式在第一次需要使用实例时才创建,避免了资源浪费。
public class LazySingleton {// 静态变量保存单例实例private static LazySingleton instance;// 私有构造方法,防止外部实例化private LazySingleton() {}// 提供公共的静态方法获取实例public static LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}
}
优点:
- 延迟加载,只有在需要时才创建实例。
缺点:
- 线程不安全,多线程环境下可能会创建多个实例。
双重检查锁定
双重检查锁定在懒汉式单例模式的基础上,使用同步块和双重检查机制来保证线程安全。
public class DoubleCheckedLockingSingleton {// volatile 确保 instance 的可见性和有序性private static volatile DoubleCheckedLockingSingleton instance;// 私有构造方法,防止外部实例化private DoubleCheckedLockingSingleton() {}// 提供公共的静态方法获取实例public static DoubleCheckedLockingSingleton getInstance() {if (instance == null) {synchronized (DoubleCheckedLockingSingleton.class) {if (instance == null) {instance = new DoubleCheckedLockingSingleton();}}}return instance;}
}
优点:
- 线程安全。
- 延迟加载,性能较好。
缺点:
- 实现较为复杂,需要理解 volatile 关键字和双重检查机制。
静态内部类
静态内部类方式利用 JVM 类加载机制来保证线程安全,同时实现延迟加载。
public class StaticInnerClassSingleton {// 私有构造方法,防止外部实例化private StaticInnerClassSingleton() {}// 静态内部类private static class SingletonHolder {private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();}// 提供公共的静态方法获取实例public static StaticInnerClassSingleton getInstance() {return SingletonHolder.INSTANCE;}
}
优点:
- 线程安全。
- 延迟加载。
- 实现简单,利用 JVM 的类加载机制,避免了同步开销。
缺点:
- 无法提前创建实例。
枚举单例
枚举单例利用枚举类型本身的特性来保证单例模式的实现,是最简单且最安全的实现方式。
public enum EnumSingleton {INSTANCE;// 可以添加其他方法public void someMethod() {// 方法实现}
}
优点:
- 线程安全。
- 防止反序列化破坏单例。
- 防止反射攻击。
缺点:
- 无法实现延迟加载(但通常不需要,因为 JVM 保证枚举类的唯一性)。
单例模式的线程安全问题
多线程环境下的单例模式
在多线程环境中,单例模式的实现需要特别注意线程安全问题。多个线程同时访问单例类的实例获取方法时,可能会导致创建多个实例,违背单例模式的初衷。为了确保单例模式在多线程环境下的正确性,需要采取一些措施来保证线程安全。
线程安全的实现方式
1. 懒汉式单例模式(线程不安全)
最简单的懒汉式单例实现并没有考虑线程安全,在多线程环境下可能会创建多个实例。
public class LazySingleton {private static LazySingleton instance;private LazySingleton() {}public static LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}
}
2. 懒汉式单例模式(线程安全,使用同步方法)
通过在 getInstance
方法上加 synchronized
关键字,确保每次只有一个线程能够执行该方法,从而保证线程安全。
public class SynchronizedLazySingleton {private static SynchronizedLazySingleton instance;private SynchronizedLazySingleton() {}public static synchronized SynchronizedLazySingleton getInstance() {if (instance == null) {instance = new SynchronizedLazySingleton();}return instance;}
}
优点:
- 简单易实现。
- 线程安全。
缺点:
- 每次调用
getInstance
方法时都需要进行同步,性能开销较大。
3. 双重检查锁定
双重检查锁定在第一次检查实例是否为 null 时不加锁,只有在实例为 null 时才进行同步操作,从而减少了同步开销。
public class DoubleCheckedLockingSingleton {private static volatile DoubleCheckedLockingSingleton instance;private DoubleCheckedLockingSingleton() {}public static DoubleCheckedLockingSingleton getInstance() {if (instance == null) {synchronized (DoubleCheckedLockingSingleton.class) {if (instance == null) {instance = new DoubleCheckedLockingSingleton();}}}return instance;}
}
优点:
- 线程安全。
- 相比同步方法,性能更高。
缺点:
- 实现复杂,需要注意
volatile
关键字的使用。
4. 静态内部类
利用 Java 的类加载机制,静态内部类在被调用时才会被加载,从而实现延迟加载和线程安全。
public class StaticInnerClassSingleton {private StaticInnerClassSingleton() {}private static class SingletonHolder {private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();}public static StaticInnerClassSingleton getInstance() {return SingletonHolder.INSTANCE;}
}
优点:
- 线程安全。
- 实现简单,延迟加载。
缺点:
- 无法防止反射攻击。
5. 枚举单例
枚举类型本身是线程安全的,并且枚举的实例是全局唯一的,可以防止反射和序列化导致的重新创建实例问题。
public enum EnumSingleton {INSTANCE;public void someMethod() {// some method}
}
优点:
- 线程安全。
- 防止反射和序列化导致的重新创建实例问题。
缺点:
- 枚举类型在某些情况下可能不适用(例如需要继承其他类)。
单例模式的序列化与反序列化
序列化导致的问题
在 Java 中,单例模式可能会由于序列化和反序列化而被破坏。具体来说,当一个单例对象被序列化到文件中,然后再从文件中反序列化回来时,会创建一个新的实例,这样就违反了单例模式的原则。
例如,考虑以下单例类:
import java.io.Serializable;public class Singleton implements Serializable {private static final long serialVersionUID = 1L;private static final Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}
}
如果我们进行序列化和反序列化操作:
import java.io.*;public class SingletonSerializationTest {public static void main(String[] args) throws Exception {Singleton instanceOne = Singleton.getInstance();// 序列化对象到文件ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("singleton.ser"));out.writeObject(instanceOne);out.close();// 从文件中反序列化对象ObjectInputStream in = new ObjectInputStream(new FileInputStream("singleton.ser"));Singleton instanceTwo = (Singleton) in.readObject();in.close();System.out.println("instanceOne hashCode: " + instanceOne.hashCode());System.out.println("instanceTwo hashCode: " + instanceTwo.hashCode());}
}
输出可能会是两个不同的哈希码,表明反序列化创建了一个新的实例。
如何防止反序列化破坏单例
为了防止反序列化破坏单例,可以在单例类中实现 readResolve
方法。这个方法在反序列化时会被自动调用,返回当前的单例实例,从而确保反序列化不会创建新的实例。
import java.io.Serializable;public class Singleton implements Serializable {private static final long serialVersionUID = 1L;private static final Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}// 添加 readResolve 方法protected Object readResolve() {return getInstance();}
}
现在,如果我们再次运行序列化和反序列化操作,输出将会是相同的哈希码,表明反序列化没有创建新的实例:
import java.io.*;public class SingletonSerializationTest {public static void main(String[] args) throws Exception {Singleton instanceOne = Singleton.getInstance();// 序列化对象到文件ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("singleton.ser"));out.writeObject(instanceOne);out.close();// 从文件中反序列化对象ObjectInputStream in = new ObjectInputStream(new FileInputStream("singleton.ser"));Singleton instanceTwo = (Singleton) in.readObject();in.close();System.out.println("instanceOne hashCode: " + instanceOne.hashCode());System.out.println("instanceTwo hashCode: " + instanceTwo.hashCode());}
}
通过实现 readResolve
方法,可以确保序列化和反序列化过程中不会破坏单例模式,从而维护单例的唯一性。
单例模式的反射攻击
反射攻击导致的问题
Java 的反射机制允许在运行时动态地创建对象、调用方法和访问字段。通过反射,可以绕过私有构造函数,直接创建单例类的新实例,从而破坏单例模式。
例如,考虑以下单例类:
public class Singleton {private static final Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}
}
使用反射可以创建新的实例:
Singleton instance1 = Singleton.getInstance();Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
Singleton instance2 = constructor.newInstance();System.out.println(instance1 == instance2); // 输出 false
如何防止反射破坏单例
为了防止反射攻击,可以在单例类的构造函数中加入防御措施,确保在构造函数被多次调用时抛出异常。
public class Singleton {private static final Singleton instance = new Singleton();private static boolean instanceCreated = false;private Singleton() {if (instanceCreated) {throw new RuntimeException("单例实例已经存在,不能创建多个实例");}instanceCreated = true;}public static Singleton getInstance() {return instance;}
}
在上述代码中,instanceCreated
标志用于检测是否已经创建过实例。如果构造函数被再次调用,则抛出异常,防止通过反射创建新的实例。
使用枚举类型防止反射和序列化攻击
使用枚举类型实现单例模式是防止反射和序列化攻击的最简单和最有效的方法。枚举类型在 Java 中是天然的单例,并且防止反射攻击和序列化攻击。
public enum EnumSingleton {INSTANCE;public void someMethod() {// some method}
}
枚举类型的单例不仅简单,而且可以防止反射和序列化导致的单例破坏问题。
单例模式的实际应用案例
数据库连接池管理
数据库连接池是一个典型的单例模式应用场景。通过单例模式,确保整个应用程序只存在一个数据库连接池实例,从而有效管理数据库连接资源。
public class DatabaseConnectionPool {private static DatabaseConnectionPool instance;private ConnectionPool pool;private DatabaseConnectionPool() {// 初始化连接池}public static synchronized DatabaseConnectionPool getInstance() {if (instance == null) {instance = new DatabaseConnectionPool();}return instance;}public Connection getConnection() {return pool.getConnection();}
}
日志管理
日志管理也是单例模式的一个常见应用。通过单例模式,确保整个应用程序使用同一个日志记录器实例,从而统一管理日志输出。
public class Logger {private static Logger instance;private Logger() {// 初始化日志配置}public static synchronized Logger getInstance() {if (instance == null) {instance = new Logger();}return instance;}public void log(String message) {// 记录日志}
}
配置文件管理
配置文件管理通常也使用单例模式,确保整个应用程序只加载一次配置文件,并提供统一的接口访问配置数据。
public class ConfigurationManager {private static ConfigurationManager instance;private Properties properties;private ConfigurationManager() {// 加载配置文件properties = new Properties();try (InputStream input = new FileInputStream("config.properties")) {properties.load(input);} catch (IOException ex) {ex.printStackTrace();}}public static synchronized ConfigurationManager getInstance() {if (instance == null) {instance = new ConfigurationManager();}return instance;}public String getProperty(String key) {return properties.getProperty(key);}
}
总结
单例模式的最佳实践
- 私有构造函数:确保构造函数是私有的,防止外部直接实例化。
- 静态方法获取实例:通过静态方法获取唯一的实例。
- 防止反射攻击:在构造函数中添加检查,防止反射攻击。
- 防止序列化破坏:实现
readResolve
方法,防止反序列化创建新的实例。 - 线程安全:在多线程环境中,使用合适的方式(如双重检查锁定、静态内部类、枚举单例)确保线程安全。
单例模式的使用建议
- 资源管理:适用于需要全局管理的资源,如数据库连接池、日志记录器、配置文件等。
- 性能考虑:在性能敏感的应用中,确保单例的创建和访问是高效的。
- 避免过度使用:虽然单例模式有其优势,但过度使用可能导致代码难以测试和维护。在设计时应慎重考虑是否真的需要单例模式。
- 测试友好:在单元测试中,可以使用依赖注入或其他设计模式来替代单例,以便于测试。
通过遵循这些最佳实践和使用建议,可以在项目中有效地应用单例模式,确保其稳定性和可维护性。
相关文章:

【设计模式】单例模式 在java中的应用
文章目录 引言什么是单例模式单例模式的应用场景单例模式的优缺点优点缺点 单例模式的基本实现饿汉式单例模式懒汉式单例模式双重检查锁定静态内部类枚举单例 单例模式的线程安全问题多线程环境下的单例模式线程安全的实现方式1. **懒汉式单例模式(线程不安全&#…...

burp suite 8
声明! 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&a…...

为什么在Java中super与this不能共存于子类构造器中,其中this起什么作用
在 Java 中,super 和 this 是两个关键字,它们在子类的构造器中有特定的用途和限制。 super 关键字: super 用于从父类(超类)访问成员(属性和方法)或者调用父类的构造方法。 在子类的构造器中&…...

Hypothesis:高效的 Python 测试工具
简介:Hypothesis 是一个强大的 Python 测试库,旨在自动生成各种测试案例,以帮助开发者发现潜在的边界问题和隐藏的错误。通过对输入数据进行智能化的探索,Hypothesis 能够为测试提供更全面的覆盖,避免遗漏一些极端或不…...

Terminus Calculator 计算原理分享
在《使命召唤:黑色行动 6》僵尸模式中,Terminus 关卡的研究办公室里有一个复杂的数学谜题需要解决。为了获得多相共振器,玩家需要计算出三个数字并输入电脑。虽然可以花费 5000 精华来获得答案,但使用 Terminus Calculator 可以更…...

Wwise 使用MIDI文件、采样音频
第一种:当采样音频只有一个文件的时候 1.拖入MIDI文件到Interactive Music Hierarchy层级 2.拖入采样音频到Actor-Mixer Hierarchy层级 3.勾选MIDI显示出面板,设置Root Note与采样音频音高相同,这里是C#5 4.播放测试,成功&…...

在CentOS上无Parallel时并发上传.wav文件的Shell脚本解决方案
在CentOS上无Parallel时并发上传.wav文件的Shell脚本解决方案 背景概述解决方案脚本实现脚本说明使用指南注意事项在CentOS操作系统环境中,若需并发上传特定目录下的.wav文件至HTTP服务器,而系统未安装GNU parallel工具,我们可通过其他方法实现此需求。本文将介绍一种利用Sh…...

【RocketMQ 源码分析(一)】设计理念与源码阅读技巧
RocketMQ 的设计理念与源码阅读技巧 一、设计理念二、源码设计三、源码阅读技巧 一直想仔细仔细看看这个 RocketMQ 的源码,学学它的设计思想和编码风格,没准在以后自己在设计和编码的时候有思考的方向。这是专栏的第一篇 —— 介绍下 RocketMQ 的一些设计…...

独立ip服务器有什么优点?
网站的性能和安全性直接影响到用户体验和业务发,独立IP服务器作为一种主流的托管方式,因其独特的优势而受到许多企业和个人站长的青睐。与共享IP相比,独立IP服务器到底有哪些优点呢? 使用独立IP的用户不必担心与其他网站共享同一…...

如何使用Python库连接Redis
1、redis-py 库封装一个 Redis 工具类可以帮助我们简化 Redis 的操作并提高代码的复用性和可维护性。 安装redis pip install redisimport redis import logginglogging.basicConfig(levellogging.INFO) logger logging.getLogger(__name__)class RedisUtils:def __init__(s…...

Vant UI +Golang(gin) 上传文件
前端基本用法:点击查看 实现代码: const afterRead (file) > {console.log(file);//set content-type to multipart/form-dataconst formData new FormData();formData.append("file", file.file);request.POST("/api/v1/users/up…...

【Unity高级】如何实现粒子系统的间歇式喷射
先看下要最终实现的效果: 代码如下: using UnityEngine; using System.Collections;public class ParticleBurstController : MonoBehaviour {private ParticleSystem _particleSystem; // 获取粒子系统public float burstDuration 2f; // 每次…...

通过linux命令获取自选股票价格及大盘涨跌幅
技术发展与数据获取需求 互联网与金融数据融合:随着互联网的普及和金融市场的数字化发展,金融数据的获取和分析变得更加便捷和重要。投资者希望能够及时、准确地获取股票价格和市场指数等信息,以便做出合理的投资决策。Linux 作为一种强大的操作系统,为数据获取和处理提供…...

透彻理解并解决Mockito模拟框架的单元测试无法运行的问题
本篇的实例基于Maven IDE (VS Code) 运行 在VS Code 运行的时候, 不需要在pom.xml 中添加任何插件就可以在测试类中看到如下的绿色按钮,单击就可以运行使用Mockito 注解 ExtendWith(MockitoExtension.class) 或是 Mockito 代码方式的测试。 不使用注…...

vue3字典数据的显示问题(使用hooks解决)
我们在使用 element-plus的时候,经常会使用一些字典数据, 在搜索框的时候,字典数数要使用 el-select el-option 来显示,当在table表格的时候,我们通常记录的是 字典数据的id , 又要把它改变成 字典数据的 name 属性 因…...

Elasticsearch 单节点安全配置与用户认证
Elasticsearch 单节点安全配置与用户认证 安全扫描时发现了一个高危漏洞:Elasticsearch 未授权访问 。在使用 Elasticsearch 构建搜索引擎或处理大规模数据时,需要启用基本的安全功能来防止未经授权的访问。本文将通过简单的配置步骤,为单节…...

二分查找(带图详解)
优选算法系列 文章目录 优选算法系列前言一、二分查找的思想二、算法使用小总结 三、代码实现四、二分查找拓展4.1、查找第一次出现的target小总结 4.2、target最后出现的位置小总结 五、代码总结 前言 在这篇博客中,我会给大家分享二分查找及其扩展。 这是链接-&…...

【Git】:标签管理
目录 理解标签 创建标签 操作标签 理解标签 标签的作用 标记版本:标签 tag ,可以简单的理解为是对某次 commit 的⼀个标识,相当于起了⼀个别名。例如,在项目发布某个版本的时候,针对最后⼀次 commit 起⼀个 v1.0 这样…...

物品识别 树莓派 5 YOLO v5 v8 v10 11 计算机视觉
0. 要实现的效果 让树莓派可以识别身边的一些物品,比如电脑,鼠标,键盘,杯子,行李箱,双肩包,床,椅子等 1. 硬件设备 树莓派 5 raspberrypi.com/products/raspberry-pi-5/树莓派官方摄…...

单片机软件工程师前景分析
单片机软件工程师的前景在2024年看起来是积极的。随着物联网(IoT)、自动化、智能设备等领域的快速发展,对于能够开发基于单片机(MCU)如STM32、ARM、51等嵌入式系统的软件工程师需求持续增长。这些工程师负责设计和实现…...

在Java中几种常用数据压缩算法的实现及其优劣势
在Java中几种常用数据压缩算法的实现及其优劣势 背景:项目需要引入Redis作为缓存组件,需要考虑到Redis的内存占用(机器内存越大,成本越高),因此需要引入数据压缩。 1、介绍 数据压缩是计算机领域中一项重要…...

Word——如何打出 符号中的 1、2、3等带圆圈的序号
一、方式1 1.1:点击 插入-符号 1.2:字体 选择 Wingdings 或者 Wingdings 2 二、方式2 带1的圈:输入 2460,然后按 AItX 带2的圈:输入 2461,然后按 AItX 带3的圈:输入 2462,然后按 …...

操作系统之进程与线程
进程 定义: 进程是具有独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度的独立单位。 组成: 包括程序代码、程序处理的数据、程序计数器、一组寄存器的值以及系统资源(如打开的文件)等。 …...

代码随想录算法训练营打卡第35天:背包问题
前言 zaccheo打卡代码随想录第35天 由于这段时间工作太忙了(加上我的懒病犯了)导致迟打卡了好几天555555.。。。 今天的主要是动态规划中的背包问题,这个真的是蛮难理解的,我把我自己强行按在椅子上半个小时一点一点的看卡哥文章…...

【MySQL】数据库 Navicat 可视化工具与 MySQL 命令行基本操作
💯 欢迎光临清流君的博客小天地,这里是我分享技术与心得的温馨角落 💯 🔥 个人主页:【清流君】🔥 📚 系列专栏: 运动控制 | 决策规划 | 机器人数值优化 📚 🌟始终保持好奇心&…...

vscode(一)安装(ubuntu20.04)
1、更新软件包列表 sudo apt update2、安装依赖包 sudo apt install software-properties-common apt-transport-https wget3、导入Microsoft GPG密钥 wget -q https://packages.microsoft.com/keys/microsoft.asc -O- | sudo apt-key add -4、向系统添加VSCode存储库 sudo…...

利用永恒之蓝对win7进行键盘记录
打开kali中的msfconsole 找到永恒之蓝,设置靶机ip,后可以exploit,也可以run 连接成功 查看进程,选择监听靶机win7上的cmd.exe进程 当前进程不是1484,需要迁移到1484 cmd.exe,进程迁移 键盘监听,…...

万字长文解读深度学习——dVAE(DALL·E的核心部件)
🌺历史文章列表🌺 深度学习——优化算法、激活函数、归一化、正则化 深度学习——权重初始化、评估指标、梯度消失和梯度爆炸 深度学习——前向传播与反向传播、神经网络(前馈神经网络与反馈神经网络)、常见算法概要汇总 万字长…...

RL仿真库pybullet
1. 介绍 PyBullet是一个基于Bullet Physics引擎的物理仿真Python接口,主要用于机器人仿真模拟。 1.1 主要特点 提供大量预设的机器人模型,例如URDF(统一机器人描述格式)、SDF、MJCF 格式。适用于训练和评估强化学习算法,提供了大量的强化学…...

file_get_contents函数导致网站卡死响应超时
宝塔控制面板系统下运行包含file_get_contents函数的php文件时候,发生以下报错: PHP Warning: file_get_contents():php_network_getaddresses: getaddrinfo failed: 解决方法: 一:需要检查请求的远程主机是否在本机的/etc/host…...