单例模式实现—考虑线程安全性

本文深入探讨了单例模式的七种实现方式,并分析了每种方式的特点与适用场景,特别是针对线程安全性的讨论。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在设计模式中,最为常见常用的应该就是单例模式了。

单例模式的使用场景:

1.资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如日志文件,应用配置。
2.控制资源的情况下,方便资源之间的互相通信。如线程池等。

单例模式要素:
  • 私有构造方法
  • 私有静态成员变量,自身类型的实例
  • 以自己实例为返回值的公有静态方法
单例模式常见的七种实现方式

——
1. 简单的懒汉模式 非线程安全

public class Sigleton1 {
    private static Sigleton1 instance;

    private Sigleton1() {
    }

    public static Sigleton1 getInstance() {
        if (instance == null) { //代码1 多线程环境下,判断是否为null这里是非线程安全的
            instance = new Sigleton1(); //代码2
        }
        return instance;
    }
}

假设线程A先判断 代码1 发现 instance 为 null 然后执行 代码2,此时线程B 执行代码1 但是线程A还没有完成对象的初始化,instance 此时为 null ,因此线程B 也会执行代码2 ,所以这不是线程安全的方法。
——
2. 采用同步的懒汉模式 线程安全

public class Sigleton2 {
    private static Sigleton2 instance;

    private Sigleton2() {
    }

    public synchronized static Sigleton2 getInstance() {
        if (instance == null) {
            instance = new Sigleton2();
        }
        return instance;
    }
}

在 getInstance() 方法加同步,线程安全性得到了保证,但是如果在多个线程频繁调用该方法的场景下,程序执行的性能会因为这里的同步而大幅下降。
——
3. 简单双重校验 非线程安全
采用双重校验理论上降低了同步的开销

public class Sigleton3 {
    private static Sigleton3 instance;

    private Sigleton3() {
    }

    public static Sigleton3 getInstance() {
        if (instance == null) {
            synchronized (Sigleton3.class) {
                if (instance == null) {
                    instance = new Sigleton3();
                }
            }
        }
        return instance;
    }
}

编译器提示安全问题:
这里写图片描述
原因是:

instance = new Sigleton3();

创建一个对象的过程可以分解为:

memory = allocate(); //1: 分配对象的内存空间
ctorInstance(memory); //2: 初始化对象
instance = memory; //3: 设置 instance 指向刚分配的内存地址

然而 代码2 和 代码3 的顺序可能会被编译器(如JIT)优化重排序,从而变成下面的执行顺序:

memory = allocate(); //1: 分配对象的内存空间
instance = memory; //3: 设置 instance 指向刚分配的内存地址
//注意对象还没有被初始化
ctorInstance(memory); //2: 初始化对象
时间线程A线程B
t1A1:分配对象的内存空间
t2A3:设置instance指向内存空间
t3B1:判断instance是否为空
t4B2:instance != null, 线程B将访问instance引用的对象
t5A2:初始化对象
t6A4:访问instance引用的对象

因此,上述的简单双重校验是危险的非线程安全实现方式。
——
4. 带volatile 的双重校验 线程安全
想把非线程安全的双重校验改成线程安全的双重校验有两种方式:
(1)禁止 2 和 3 的重排序
(2)允许 2 和 3 的重排序,但不允许其他线程“看到” 这个重排序。
基于上述第一个方法,只需要对实现3的简单实现做简单修改,对instance加上volatile即可:

public class Sigleton3 {
    private volatile static Sigleton3 instance;
// volatile 禁止对volatile写和volatile写前面任意内存操作重排序
// volatile 禁止对volatile读和volatile读后面任意内存操作重排序
// volatile 将修改后的值立刻刷新到内存,保证内存可见性
    private Sigleton3() {
    }

    public static Sigleton3 getInstance() {
        if (instance == null) {
            synchronized (Sigleton3.class) {
                if (instance == null) {
                    instance = new Sigleton3();
                }
            }
        }
        return instance;
    }
}

——
5. 饿汉模式 线程安全

public class Sigleton5 {
    private static Sigleton5 instance = new Sigleton5();

    private Sigleton5() {}

    public static Sigleton5 getInstance() {
        return instance;
    }
}

因为没有重复判断 instance 所以不存在线程安全性问题。
——
6. 基于类初始化的解决方案——静态内部类 线程安全 推荐

public class Sigleton6 {
    private Sigleton6() { }

    private static class SigletonHolder {
        private static final Sigleton6 instance = new Sigleton6();
    }

    public static Sigleton6 getInstance() {
        return SigletonHolder.instance;
    }
}

——
7. 基于枚举的单例模式 线程安全

public enum Sigleton {
    instance;
}

Over,再也不怕面试官让手撸单例模式了!

### 使用Python实现台风中心定位的方法 对于台风中心的精确定位,通常依赖于气象观测数据和数值天气预报模式的结果。在实践中,可以利用多种方法来估计台风的位置,包括但不限于最小风速法、气压场分析以及卫星云图识别技术。 #### 方法一:基于最低海平面气压位置 一种简单而常用的方式是从给定时间段内的多个站点获取海平面气压读数,并找到其中最低的那个作为潜在的风暴眼所在之处。这种方法假设低压区即为热带气旋的核心部位。 ```python import numpy as np def find_lowest_pressure_center(pressures): """ 寻找最低压力点以确定可能存在的台风中心。 参数: pressures (list of tuples): [(latitude, longitude, pressure), ...] 返回: tuple: 台风中心坐标 (lat, lon),如果未发现合适的候选,则返回None """ min_press = float('inf') center_location = None for lat, lon, press in pressures: if press < min_press: min_press = press center_location = (lat, lon) return center_location ``` 此段代码定义了一个名为`find_lowest_pressure_center()` 的函数,它接收一系列包含纬度、经度及其对应的海平面气压值组成的三元组列表作为输入参数,并输出最有可能代表当前时刻台风中心坐标的二元组[^1]。 #### 方法二:应用图像处理算法到可见光/红外线遥感影像上 另一种更为复杂但也更精确的技术涉及使用计算机视觉库(如OpenCV)配合机器学习框架对来自地球同步轨道卫星拍摄得到的高分辨率图片序列执行边缘检测、形态学变换等一系列操作后提取出涡旋结构特征并据此推断出台风的具体方位。 ```python import cv2 from skimage import io def detect_eye_from_satellite_image(image_path): """ 利用图像处理手段从未知状态下的静止卫星图像中自动辨识出飓风水汽漩涡核心部分。 参数: image_path (str): 卫星图像文件路径 返回: tuple or NoneType: 如果成功找到了疑似眼睛区域,则给出其边界矩形左上角顶点坐标(x,y)及宽高等几何属性; 否则返回None表示未能完成匹配过程。 """ img = io.imread(image_path) gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) _, threshed = cv2.threshold(gray_img, 170, 255, cv2.THRESH_BINARY_INV|cv2.THRESH_OTSU) contours,hierarchy=cv2.findContours(threshed,cv2.RETR_EXTERNAL ,cv2.CHAIN_APPROX_SIMPLE)[-2:] eye_candidate=None max_area=0 for cnt in contours: area=cv2.contourArea(cnt) if area>max_area and area<image.shape[0]*image.shape[1]/8 : # 过滤掉过大的轮廓以防误判陆地等非目标物体 rect=cv2.boundingRect(cnt) max_area=area eye_candidate=(rect[0],rect[1],rect[2],rect[3]) return eye_candidate ``` 上述脚本展示了如何加载一张JPEG格式的卫星照片并通过设定阈值得到黑白两色版本以便后续计算;接着调用了 OpenCV 库里的 API 来寻找所有封闭曲线并将面积最大的那个视为可能是我们感兴趣的对象——也就是所谓的“眼睛”。最后一步则是根据这个最大连通分量绘制包围盒从而直观展示出结果[^2]。 #### 结合深度学习模型提高准确性 随着人工智能的发展,越来越多的研究人员尝试构建专门针对特定应用场景设计过的卷积神经网络(CNNs)或其他类型的深层架构来进行更加精准高效的自动化分类任务。这类方案往往需要大量标注样本支持训练阶段的工作,但在测试环境下却能展现出超越传统统计物理建模的优势特性。 例如,在某些情况下,即使当常规探测设备失效或者无法覆盖整个影响范围时,经过良好训练后的AI系统仍然可以从有限的信息源里挖掘出有用线索进而辅助决策者做出科学合理的判断[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值