较个真!Matirx 单例写法的线程安全问题

CV::MAT总结 CV::MAT1 基础知识MAT是opencv2.X里面新出现配合C++的n-dimensional dense array class。强烈推荐大家使用 我们先看一下结构:class CV_EXPORTS Mat { public: // ... a lot of methods ... ... /*! includes several bit-fields: 阅读详情

最近看了看 Matrix 的源码,无意间看到一个单例的写法。因为这种写法比较特殊,所以花了些时间认真看了下。发现还真的有点问题。当然,其实问题也不大。因为这种单例的问题在没有并发的情况下出现的概率比较低。所以我说“较个真”而已。

问题出现在 FrameDecorator 获取实例的静态方法。看这个写法的意思就是获取一个单例的 FrameDecorator. 不过,因为这里在创建单例的时候需要用到 FloatFrameView 这个控件。因为在 Android 中存在这样一个限制:只有创建一个 View 的线程才能对它进行修改(并不强制是主线程)。所以,如果我们想要在主线程当中使用这个控件就要求创建 View 的时候就应该在主线程中创建。

从这个方法的逻辑可以看出,这里希望,当当前线程是主线程的时候直接创建 FrameDecorator 实例,当当前线程不是主线程的时候就将创建 FrameDecorator 的操作 post 到主线程中执行。

public static FrameDecorator getInstance(final Context context) {
    if (instance == null) {
        if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
            instance = new FrameDecorator(context, new FloatFrameView(context));
        } else {
            try {
                synchronized (lock) {
                    mainHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            instance = new FrameDecorator(context, new FloatFrameView(context));
                            synchronized (lock) {
                                lock.notifyAll();
                            }
                        }
                    });
                    lock.wait();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    return instance;
}

这里通过可重入锁 synchronized 实现私有锁进行局部加锁以降低锁粒度。

这里有一个问题,当子线程通获取到 lock 的锁的时候,主线程在 synchronized 的时候是如何获取到锁的呢?这是因为当在子线程中调用 wait 方法的时候,会阻塞并且会同时释放 lock 的锁。所以,主线程当中可以通过 synchronized 获取到 lock 的锁。

经常拿来和 wait 做对比的 sleep 虽然在被调用的时候一样可以让当前线程阻塞,但是不会释放锁的,并且只能通过中断的方式结束阻塞。这是两者之间的区别。

写个例子对比一下,

new Thread(() -> {
    try {
        synchronized (lock) {
            new Thread(() -> {
                synchronized (lock) {
                    System.out.println("do business in child thread."); // 2
                    lock.notifyAll();
                }
            }).start();
            System.out.println("do business in main thread before wait."); // 1
            lock.wait();
            System.out.println("do business in main thread after wait."); // 3
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}).start();

执行顺序如上述代码所示,即调用 wait 的时候锁被释放,此时,子线程获取到锁,2 被执行,然后 notify 被调用,阻塞被移除,3 被调用。

换成 sleep,

new Thread(() -> {
    try {
        synchronized (lock) {
            new Thread(() -> {
                synchronized (lock) {
                    System.out.println("do business in child thread."); // 3
                }
            }).start();
            System.out.println("do business in main thread before wait."); // 1
            Thread.sleep(1_000);
            System.out.println("do business in main thread after wait."); // 2
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}).start();

锁不会释放,执行结果是,3 必须在 2 完成之后,锁被释放了才能执行。即,

do business in main thread before wait.
do business in main thread after wait.
do business in child thread.

基于 wait+notifyAll 的思路似乎没有什么问题。那么这种单例写法是否存在线程安全问题?答案是会。

这主要的原因是,

  1. 第一,虽然 `mainHandler.post()` 的逻辑位于 `wait()` 的前面,但是不能因此而断定 `mainHandler.post()` 内的逻辑就一定在 `wait()` 之前被执行。因为 Handler 是一个消息队列机制,消息本身是需要排队的。可以将 Handler 看作一个单线程的线程池,不过即便如此也无法保证任务被加入到线程池之后立即执行。

  2. 第二,当调用 `wait()` 方法释放锁的时候,此时,主线程和子线程对 lock 处于竞争状态。也就是说,此时子线程仍然有可能竞争到锁而进入同步代码块。也就是,可能会向主线程当中 post 两条创建实例的消息。因此,也就会出现创建多个单例的情况。

我们可以写一个测试程序来模拟下,

public class LockTest {

    private static final Object lock = new Object();

    private static final Executor executor = Executors.newSingleThreadExecutor();

    private static LockTest instance;

    public static void main(String...args) {
        for (int i=0; i<200; i++) {
            new Thread(() -> System.out.println(getInstance())).start();
        }
    }

    private static LockTest getInstance() {
        if (instance == null) {
            try {
                synchronized (lock) {
                    executor.execute(() -> {
                        instance = new LockTest();
                        synchronized (lock) {
                            lock.notifyAll();
                        }
                    });
                    lock.wait();
                }
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
        return instance;
    }
}

这里通过单例的线程池来模拟消息被 post 到主线程的情况。输出的部分结果如下。也就是会出现线程安全问题的,

...
me.shouheng.LockTest@776d8031
me.shouheng.LockTest@776d8031
me.shouheng.LockTest@735037e6
me.shouheng.LockTest@59a30351
me.shouheng.LockTest@59a30351
me.shouheng.LockTest@31d0f5c9
me.shouheng.LockTest@31d0f5c9
me.shouheng.LockTest@735037e6
me.shouheng.LockTest@735037e6
me.shouheng.LockTest@735037e6
...

那么如何解决呢? 只需要在实例化的时候做一层判断就可以了。为什么呢?因为实例化操作总是在主线程中执行,也就是说实例化的操作是线性执行的。因此是不存在线程安全问题的,

private static LockTest getInstance() {
    if (instance == null) {
        try {
            synchronized (lock) {
                executor.execute(() -> {
                    if (instance == null) {
                        instance = new LockTest();
                    }
                    synchronized (lock) {
                        lock.notifyAll();
                    }
                });
                lock.wait();
            }
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }
    return instance;
}

这种写法的输出结果都是同一个实例,就不贴出来了。

这种单例写法在安卓当中出现问题的概率并不大。我们开发当中应该会有机会遇到这种单例的情况(需要在主线程当中闯将 view 的时候)。不过根据墨菲定律——如果事情有变坏的可能,不管这种可能性有多小,它总会发生。写代码还是要严谨的,估计吃过亏的都会懂。

 

 如何入门学习网络安全

零基础入门

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

同时每个成长路线对应的板块都有配套的视频提供:

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

优快云大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享

视频配套资料&国内外网安书籍、文档&工具

当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料&工具,并且已经帮大家分好类了。
在这里插入图片描述

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

优快云大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享

11. TI MSPM0G3507 DMA传输实战:ADC数据自动搬运与电压采集 本文以TI MSPM0G3507为例,详细讲解了如何利用DMA(直接存储器访问)实现ADC数据的自动搬运与电压采集。通过实战演示,解放CPU资源,提升系统实时性与效率,适用于电赛备赛及嵌入式开发中的数据采集场景。 阅读详情

相关推荐

数据仓库实践:从ITR流程讲指标体系建设

从 ITR 流程或者其他客服反馈流程的考核过程可见,实际工作中不可能只通过单个指标评价一个业务过程,需要从多个维度梳理业务,并把多个高度相关的指标组织起来,以避免只考虑其中某个指标从而摧毁整个业务过程的结果,指标体系=指标+体系。

the_singing_towers的博客 2268

OpenCV参考手册之Mat类详解(三)

Mat::eye 返回一个恒等指定大小和类型矩阵。 C++: static MatExpr Mat::eye(int rows, int cols, inttype) C++: static MatExpr Mat::eye(Size size, int type) 参数 rows –的行数。 cols– 的列数。 size –替代矩阵大小规格Size(cols, rows)的方法。

giantchen 11万+

从USB相机标定到Aruco码精准定位:基于aruco-ros的机器人视觉实践

本文详细介绍了基于aruco-ros的机器人视觉实践,从USB相机标定到Aruco码精准定位的全流程。通过实战案例和优化技巧,展示了Aruco码在机器人导航中的高精度位姿识别能力,帮助开发者快速实现毫米级视觉定位系统。

weixin_27310417的博客 487

关于线程安全的涉及到概念以及分类

本文摘选自深入理解Java虚拟机。 方法一:互斥同步(Matual Exclusion &amp; Synchronization) 互斥同步属于一种悲观的并发策略,总是认为只要不去做正确的同步措施,就肯定会出现问题。无论共享数据是否出现竞争,它都要进行加锁。故称互斥同步的锁为悲观锁 ①使用synchronized关键字。synchronized同步代码块对同一个线程来说是可重入的,不会出...

岁末的枫雨 1204

《点亮创新灯塔!AI应用架构师与中小学初等教育AI智能体,共筑智能化教育辅助创新灯塔》

中小学AI智能体,是基于AI技术,能感知教育场景、理解教育规律、辅助教师教学和学生学习的智能系统。做老师“做不了”的事:比如5分钟批改45本作业,精准统计每个学生的易错点;做老师“做不好”的事:比如根据学生的学习风格(视觉/听觉/动觉)推荐个性化内容;绝不做老师“该做的事”:比如情感交流、价值观引导、创意教学设计——这些“人的温度”,AI永远无法替代。我是林宇,资深AI应用架构师,专注教育AI领域8年,参与过10多个中小学AI智能体项目,曾为北京、上海、深圳等城市的100多所学校提供AI教育解决方案。

Java大师兄的博客 433

STM32F407通过SMBus协议精准读取BQ40Z50电池电量

本文详细介绍了STM32F407通过SMBus协议精准读取BQ40Z50电池电量的实现方法。从硬件连接到软件驱动开发,再到通信异常排查,提供了完整的解决方案。重点解析了SMBus协议的特殊时序要求、GPIO模拟驱动的关键代码,以及实际调试中的常见问题与对策,帮助开发者高效完成电池管理系统开发。

weixin_29189003的博客 253

OpenCV Mat类详解和用法

OpenCV Mat类详解和用法      我们有多种方法可以获得从现实世界的数字图像:数码相机、扫描仪、计算机体层摄影或磁共振成像就是其中的几种。在每种情况下我们(人类)看到了什么是图像。但是,转换图像到我们的数字设备时我们的记录是图像的每个点的数值。       例如在上图中你可以看到车的镜子只是一个包含所有强度值的像素点矩阵。现在,我们如何获取和存储像素值可能根据最适合我们的需要而变...

AI吃大瓜的博客 16万+

18006.STM32通过SPI读取LAN9253数据

【代码】18006.STM32通过SPI读取LAN9253数据。

写给自己的笔记 556

opencv中的线程安全问题

最近做的项目需要实现多线程播放多路视频,但是代码经常会报insufficient thread locking around avcodec_open/close()的错误,因为在机子上貌似也能跑,就暂时没理。  今天换成在服务器上测试,因为cup速度加快,线程冲突加剧,cvCreateFileCapture((char*)pName)经常返回空指针。opencv官方并没有保证函数都是线程安

陆业聪 2598

pyecharts在jupyter notebook中不能够渲染图表问题。

在使用jupyter notebook中使用pyecharts绘制可视化图表的时候,发现图表不能渲染到页面中,生成的html是没问题的,本文主要解决在jupyter notebook中不能渲染这个问题。

猿小白的博客 1170

高通Camx相机防抖分析分析一:概率性EIS防抖功能失效

摘要:文章分析了高通Camx平台EIS电子防抖失效问题。通过日志排查发现NCS服务在启动时出现gyro传感器探测超时(error 9),导致无法获取陀螺仪数据。虽然sensor模块上电和注册正常,但由于性能问题触发了超时机制。解决方案是增大QSEEConnectionTimeout阈值,经测试有效解决了该问题。后续文章将继续深入相关技术专题。

627

湖南省网安基地网络安全培训:零基础入门与实战进阶的课程衔接

零基础学网安,怕跟不上;有基础再学,怕重复。本文按阶段拆解湖南省网安基地的网络安全培训衔接逻辑:能力评估定起点,基础阶段补系统与网络底座,核心阶段练漏洞复现,进阶阶段进入红蓝对抗与单位网络安全攻防演练,并说明 NISP、CISP 与网安实战人才的对应关系。

2401_84466325的博客 1136

11、系统稳定性分析与李雅普诺夫函数的应用

本文深入探讨了李雅普诺夫函数在系统稳定性分析中的核心作用,重点介绍了时变与时不变系统的稳定性判据差异,以及巴尔巴拉特引理在处理非自治系统中的应用。文章还阐述了正线性系统与严格正实传递函数的性质及其在非线性控制系统中的重要性,并展示了李雅普诺夫函数在评估主导时间常数和设计快速干扰抑制控制策略方面的实际应用。通过具体示例和流程图,系统地总结了李雅普诺夫方法在稳定性分析、性能评估与控制器设计中的多维度价值,同时指出了当前挑战与未来发展方向。

Jerry的专栏 93

从被动整改到主动防御:网络安全测评六问六答

中金金融认证中心(CFCA)长期从事金融安全检测,站在独立第三方立场,可提供等级保护测评、渗透测试、代码审计、应用安全测试、数据安全风险评估、APP检测、大模型安全检测等服务。渗透测试、漏洞扫描、等保测评、安全评估——工具不少,报告也年年出,可一到整改,很多机构还是卡在同一个地方:问题清单列了很长,先改哪个没把握;问题往往不在做没做,而在做完之后怎么用。机构可以建立漏洞台账,明确责任部门、整改时限,整改完成后安排复测验证,形成完整留痕材料,真正把测评成果转化为安全能力,避免“测评归测评,风险归风险”。

AIpress的博客 194

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

MAI-Cyber-1 深度解析:微软首个网络安全专用模型

微软没有去做"更大的安全大模型",而是用一颗 137B 总参、仅 5B 激活的稀疏 MoE 专用模型,配上 90/10 的"小模型铺量、大模型兜底"路由,在 CyberGym 基准上拿到 95.95% 的同时把成本砍掉一半——这标志着 AI 安全从"通用模型加提示词"进入了"专用模型加系统工程"的时代。

Simple_Pure的博客 338

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

2026年11月第1周网络安全形势周报

补丁链条失守”、AI代理攻击产业化、OT/IoT 暴露面失守。在野利用密集新增:CISA KEV 本周新增 3 个已在野利用漏洞——WordPress 核心 TOCTOU 竞态(CVE-2026-119977,24小时内观测到 5.9 万次攻击尝试)、Apple 多产品指针认证绕过(CVE-2024-27834)、SonicWall SonicOS SSLVPN 单因素认证绕过(CVE-2026-19868)。

Bruce_xiaowei的博客 302

网络安全实战第29期:一次考核暴露的判断力短板

本文复盘一次网络安全综合考核,强调“流程顺序”比背命令更重要。考核聚焦判断力:信息收集、注入分析、脚本执行、文件上传与影响面记录五大环节,分值侧重判断(70分)。作者在脚本执行中因未重测过滤规则卡顿25分钟,暴露“换级不重测”的致命习惯。关键结论:防护有效≠做了防护,需验证实际效果。自评表中“扣分原因”远比分数有价值,揭示改进方向。最终用时4小时20分钟,成绩优秀,核心收获是——流程可靠,胜过技巧堆砌。

2401_88349202的博客 230

网络安全的注意事项以及解决办法

案例一:小王收到邮件,点击邮件后打开附件,此时弹出勒索病毒,打开资源管理器,清点被感染的文件数,10分钟后,财务部服务器报告异常,管理员紧急上网搜索应对措施,事后发现造成巨大损失,管理员的做法有哪些不妥?正确做法:根据业务部门和工作智能,对网络进行分区,例如:用户网络,服务器网络,财务部门网络,管理层网络之间通过防火墙或ACL(访问控制列表)进行隔离,只开放必要的业务端口,阻止不必要的横向通信。正确做法:立即隔离。整个事件链中,管理员的一系列反应是典型的,错误的应急响应操作,最终导致了损失的扩大。

2401_86853478的博客 136

IP 地址是什么?从 IPv4/IPv6、公网与私网到 NAT 与安全日志|网络安全其实很简单

本文主要讲解:IP 地址究竟表示什么?为什么同一设备会有多个 IP?一条安全告警里的源 IP 又能证明什么?

w1955587824的博客 311

网络安全与信息安全:有什么区别?

信息安全也常被称作“数据安全”。保护信息与信息系统,防止未授权访问、使用、泄露、中断、篡改或销毁,以此保障保密性、完整性与可用性。如今企业大量业务数据存储在计算机系统和云端,但过去数据是放在实体文件柜里的。存储方式变了,可有些机密敏感信息依旧以实体形式保存。信息安全的核心,是保障所有格式的数据安全。网络安全指保护计算机、服务器、网络、移动设备等电子系统中存储的数字信息,抵御未授权访问和各类恶意威胁。网络安全工作需要识别重要数据、定位数据存储位置、评估潜在风险,再选用对应的方法与工具抵御各类风险。

雪兽软件 309

浏览器输入 URL 后发生了什么?从 DNS、TCP、TLS、HTTP 到网页渲染|网络安全其实很简单

本文系统解析了浏览器访问网页的完整流程:从URL解析、DNS查询、TCP连接建立,到TLS加密、HTTP请求响应,最终渲染页面。强调安全研判中三大关键边界:DNS查询≠访问成功,TCP连接≠业务成功,HTTP 200≠攻击得逞。建议结合开发者工具与多层日志综合判断,避免误判。

w1955587824的博客 448

DeepSeek 大模型网络安全及安全级别

公开的安全通报与安全研究反复指出,未做访问控制的本地大模型推理服务(如 Ollama 一类框架的默认端口)是近年被批量扫描利用的主要目标之一。这一点对数据泄露的定性很重要——风险主要来自“记忆化(memorization)”的统计残留,而不是数据库式读取,因此防护手段是训练数据去重与清洗,而不是简单的“封库”。在用户数据的使用上,官方给出的边界是:经安全加密技术处理、严格去标识化且无法重新识别特定个人后,才可能将输入输出用于模型训练优化,并提供“数据用于优化体验”的关闭开关,关闭后不再用于训练。

linktokenview的博客 177
上一篇: 聊聊白帽子与审核的对立面
下一篇: New免杀工具NPS更新5.21(附下载)
程序员_大白
博客等级 码龄5年 1万+粉丝 4001原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值