综述:目标检测中的多尺度检测方法

article/2025/9/29 23:07:44

传统卷积网络通常采用从上到下的单行结构。对于大物体而言,其语义信息将出现在较深的特征图中;而对于小物体,其语义信息出现在较浅的特征图中,随着网络的加深,其细节信息可能会完全消失。

多尺度检测也是当今物体检测领域最为活跃的研究主题之一,本文主要介绍:多尺度检测

多尺度是目标检测与图像分类两个任务的一大区别。分类问题通常针对同一种尺度,如ImageNet中的224大小;而目标检测中,模型需要对不同尺度的物体都能检测出来,这要求模型对于尺度要具有鲁棒性。

在多尺度的物体中,大尺度的物体由于面积大、特征丰富,通常来讲较为容易检测。难度较大的主要是小尺度的物体,而这部分小物体在实际工程中却占据了较大的比例。通常认为绝对尺寸小于32×32的物体,可以视为小物体或者物体宽高是原图宽高的1/10以下,可以视为小物体。

小物体由于其尺寸较小,可利用的特征有限,这使得其检测较为困难。当前的检测算法对于小物体并不友好,体现在以下4个方面:

1、过大的下采样率:假设当前小物体尺寸为15×15,一般的物体检测中卷积下采样率为16,这样在特征图上,过大的下采样率使得小物体连一个像素点都占据不到。

2、过大的感受野:在卷积网络中,特征图上特征点的感受野比下采样率大很多,导致在特征图上的一个点中,小物体占据的特征更少,会包含大量周围区域的特征,从而影响其检测结果。 

3、语义与空间的矛盾:当前检测算法,如Faster RCNN,其Backbone大都是自上到下的方式,深层与浅层特征图在语义性与空间性上没有做到更好的均衡。 

4、SSD一阶算法缺乏特征融合:SSD虽然使用了多层特征图,但浅层的特征图语义信息不足,没有进行特征的融合,致使小物体检测的结果较差。

多尺度的检测能力实际上体现了尺度的不变性,当前的卷积网络能够检测多种尺度的物体,很大程度上是由于其本身具有超强的拟合能力。

较为通用的提升多尺度检测的经典方法有:

降低下采样率与空洞卷积可以显著提升小物体的检测性能;设计更好的Anchor可以有效提升Proposal的质量;多尺度的训练可以近似构建出图像金字塔,增加样本的多样性;特征融合可以构建出特征金字塔,将浅层与深层特征的优势互补。下面将详细介绍:

1 降低下采样率与空洞卷积

对于小物体检测而言,降低网络的下采样率通常的做法是直接去除掉Pooling层。

例如,将原始的VGGNet-16作为物体检测的Backbone时,通常是将第5个Pooling层之前的特征图作为输出的特征图,一共拥有4个Pooling层,这时下采样率为16。为了降低下采样率,我们可以将第4个Pooling层去掉,使得下采样率变为8,减少了小物体在特征图上的信息损失。

但是,如果仅仅去除掉Pooling层,则会减小后续层的感受野。如果使用预训练模型进行微调(Fine-tune),则仅去除掉Pooling层会使得后续层感受野与预训练模型对应层的感受野不同,从而导致不能很好地收敛。

因此,需要在去除Pooling的前提下增加后续层的感受野,使用空洞卷积可以在保证不改变网络分辨率的前提下增加网络的感受野。

需要注意的是,采用空洞卷积也不能保证修改后与修改前的感受野完全相同,但能够最大限度地使感受野在可接受的误差内。

2 多尺度训练 

多尺度类似于数字图像处理中的图像金字塔,即将输入图片缩放到多个尺度下,每一个尺度单独地计算特征图,并进行后续的检测。这种方式虽然一定程度上可以提升检测精度,但由于多个尺度完全并行,耗时巨大。

多尺度训练(Multi Scale Training, MST)通常是指设置几种不同的图片输入尺度,训练时从多个尺度中随机选取一种尺度,将输入图片缩放到该尺度并送入网络中,是一种简单又有效的提升多尺度物体检测的方法。

虽然一次迭代时都是单一尺度的,但每次都各不相同,增加了网络的鲁棒性,又不至于增加过多的计算量。而在测试时,为了得到更为精准的检测结果,也可以将测试图片的尺度放大,例如放大4倍,这样可以避免过多的小物体。

多尺度训练是一种十分有效的trick方法,放大了小物体的尺度,同时增加了多尺度物体的多样性,在多个检测算法中都可以直接嵌入,在不要求速度的场合或者各大物体检测竞赛中尤为常见。

3 优化Anchor尺寸设计

现今较为成熟的检测算法大都采用Anchor作为先验框,如Faster RCNN和SSD等。模型在Anchor的基础上只需要去预测其与真实物体边框的偏移即可,可以说是物体检测算法发展中的一个相当经典的设计。

Anchor通常是多个不同大小与宽高的边框,这个大小与宽高是一组超参数,需要我们手动配置。在不同的数据集与任务中,由于物体的尺度、大小会有差距,例如行人检测的数据集中,行人标签宽高比通常为0.41,与通用物体的标签会有所区别,这时就需要相应地调整Anchor的大小与宽高。

如果Anchor设计的不合理,与数据集中的物体分布存在差距,则会给模型收敛带来较大的困难,影响模型的精度,甚至不会收敛。

另外,Anchor的设计对于小物体的检测也尤为重要,如果Anchor过大,即使小物体全部在Anchor内,也会因为其自身面积小导致IoU低,从而造成漏检。

通常来讲,可以从以下两个角度考虑如何设计一组好的Anchor。

1.   统计实验,手工设计

在Faster RCNN的RPN阶段,所有Anchor会与真实标签进行匹配,根据匹配的IoU值得到正样本与负样本,正样本的IoU阈值为0.7。在这个过程中,Anchor与真实标签越接近,正样本的IoU会更高,RPN阶段对于真实标签的召回率会越高,正样本也会更丰富,模型效果会更好。

因此,可以仅仅利用训练集的标签与设计的Anchor进行匹配试验,试验的指标是所有训练标签的召回率,以及正样本的平均IoU值。当然,也可以增加每个标签的正样本数、标签的最大IoU等作为辅助指标。

为了方便地匹配,在此不考虑Anchor与标签的位置偏移,而是把两者的中心点放在一起,仅仅利用其宽高信息进行匹配。这种统计实验实际是通过手工设计的方式,寻找与标签宽高分布最为一致的一组Anchor。

2.边框聚类

相比起手工寻找标签的宽高分布,也可以利用聚类的思想,在训练集的标签上直接聚类出一组合适的Anchor。由于一组Anchor会出现在特征图的每一个位置上,因此没有位置区别,可以只关注标签里的物体宽高,而没必要关心物体出现的位置。

边框聚类时通常使用K-Means算法,这也是YOLO采用的Anchor聚类方法。K-Means算法输入超参数K,即最终想要获得的边框数量,首先随机选取K个中心点,然后遍历所有的数据,并将所有的边框划分到最近的中心点中。在每个边框都落到不同的聚类后,计算每一个聚类的平均值,并将此平均值作为新的中心点。重复上述过程,直到算法收敛。

在聚类过程中,Anchor的数量K是一个较为重要的超参,数量越多,精度越高,但与此同时会带来计算量的增加。对于使用Anchor的物体检测算法而言,设计一组好的Anchor是基础,这对于多尺度、拥挤等问题都有较大的帮助。

4 深层和浅层特征融合

传统的卷积网络通常是自上而下的模式,随着网络层数的增加,感受野会增大,语义信息也更为丰富。这种自上而下的结构本身对于多尺度的物体检测就存在弊端,尤其是小物体,其特征可能会随着深度的增加而渐渐丢失,从而导致检测性能的降低。

可以将深层的语义信息添加到浅层的特征图中,融合两者的特征,优势互补,从而提升对于小物体的检测性能。

特征融合有多种方式,增大特征图尺寸可以使用上采样、反卷积等,融合方法有逐元素相加、相乘和通道拼接等,具体哪种效果更好,还要看实际的检测任务及使用的检测算法。特征融合的普遍缺点是通常会带来一定计算量的增加。

特征融合方法示例:

1. FPN(Feature Pyramid Network)

将深层信息上采样,与浅层信息逐元素地相加,从而构建了尺寸不同的特征金字塔结构,性能优越,现已成为目标检测算法的一个标准组件。FPN的结构如下所示。

 

自下而上:最左侧为普通的卷积网络,默认使用ResNet结构,用作提取语义信息。C1代表了ResNet的前几个卷积与池化层,而C2至C5分别为不同的ResNet卷积组,这些卷积组包含了多个Bottleneck结构,组内的特征图大小相同,组间大小递减。

自上而下:首先对C5进行1×1卷积降低通道数得到P5,然后依次进行上采样得到P4、P3和P2,目的是得到与C4、C3与C2长宽相同的特征,以方便下一步进行逐元素相加。这里采用2倍最邻近上采样,即直接对临近元素进行复制,而非线性插值。

横向连接(Lateral Connection):目的是为了将上采样后的高语义特征与浅层的定位细节特征进行融合。高语义特征经过上采样后,其长宽与对应的浅层特征相同,而通道数固定为256,因此需要对底层特征C2至C4进行11卷积使得其通道数变为256,然后两者进行逐元素相加得到P4、P3与P2。由于C1的特征图尺寸较大且语义信息不足,因此没有把C1放到横向连接中。

卷积融合:在得到相加后的特征后,利用3×3卷积对生成的P2至P4再进行融合,目的是消除上采样过程带来的重叠效应,以生成最终的特征图。

FPN对于不同大小的RoI,使用不同的特征图,大尺度的RoI在深层的特征图上进行提取,如P5,小尺度的RoI在浅层的特征图上进行提取,如P2。FPN的代码实现如下:

import torch.nn as nnimport torch.nn.functional as Fimport math
class Bottleneck(nn.Module):    expansion = 4    def __init__(self, in_planes, planes, stride=1, downsample=None):        super(Bottleneck, self).__init__()        self.bottleneck = nn.Sequential(                nn.Conv2d(in_planes, planes, 1, bias=False),                nn.BatchNorm2d(planes),                nn.ReLU(inplace=True),                nn.Conv2d(planes, planes, 3, stride, 1, bias=False),                nn.BatchNorm2d(planes),                nn.ReLU(inplace=True),                nn.Conv2d(planes, self.expansion * planes, 1, bias=False),                nn.BatchNorm2d(self.expansion * planes),            )        self.relu = nn.ReLU(inplace=True)        self.downsample = downsample    def forward(self, x):        identity = x        out = self.bottleneck(x)        if self.downsample is not None:            identity = self.downsample(x)        out += identity        out = self.relu(out)        return out
class FPN(nn.Module):    def __init__(self, layers):        super(FPN, self).__init__()        self.inplanes = 64        self.conv1 = nn.Conv2d(3, 64, 7, 2, 3, bias=False)        self.bn1 = nn.BatchNorm2d(64)        self.relu = nn.ReLU(inplace=True)        self.maxpool = nn.MaxPool2d(3, 2, 1)
        self.layer1 = self._make_layer(64, layers[0])        self.layer2 = self._make_layer(128, layers[1], 2)        self.layer3 = self._make_layer(256, layers[2], 2)        self.layer4 = self._make_layer(512, layers[3], 2)        self.toplayer = nn.Conv2d(2048, 256, 1, 1, 0) 
        self.smooth1 = nn.Conv2d(256, 256, 3, 1, 1)        self.smooth2 = nn.Conv2d(256, 256, 3, 1, 1)        self.smooth3 = nn.Conv2d(256, 256, 3, 1, 1)
        self.latlayer1 = nn.Conv2d(1024, 256, 1, 1, 0)        self.latlayer2 = nn.Conv2d( 512, 256, 1, 1, 0)        self.latlayer3 = nn.Conv2d( 256, 256, 1, 1, 0)
    def _make_layer(self, planes, blocks, stride=1):        downsample  = None        if stride != 1 or self.inplanes != Bottleneck.expansion * planes:            downsample  = nn.Sequential(                nn.Conv2d(self.inplanes, Bottleneck.expansion * planes, 1, stride, bias=False),                nn.BatchNorm2d(Bottleneck.expansion * planes)            )        layers = []        layers.append(Bottleneck(self.inplanes, planes, stride, downsample))        self.inplanes = planes * Bottleneck.expansion        for i in range(1, blocks):            layers.append(Bottleneck(self.inplanes, planes))        return nn.Sequential(*layers)
    def _upsample_add(self, x, y):        _,_,H,W = y.shape        return F.upsample(x, size=(H,W), mode='bilinear') + y
    def forward(self, x):
        c1 = self.maxpool(self.relu(self.bn1(self.conv1(x))))        c2 = self.layer1(c1)        c3 = self.layer2(c2)        c4 = self.layer3(c3)        c5 = self.layer4(c4)
        p5 = self.toplayer(c5)        p4 = self._upsample_add(p5, self.latlayer1(c4))        p3 = self._upsample_add(p4, self.latlayer2(c3))        p2 = self._upsample_add(p3, self.latlayer3(c2))
        p4 = self.smooth1(p4)        p3 = self.smooth2(p3)        p2 = self.smooth3(p2)        return p2, p3, p4, p5

2. DetNet:专为目标检测而生的Backbone,利用空洞卷积与残差结构,使得多个融合后的特征图尺寸相同,从而也避免了上采样操作。

3. Faster RCNN系列中,HyperNet将第1、3、5个卷积组后得到的特征图进行融合,浅层的特征进行池化、深层的特征进行反卷积,最终采用通道拼接的方式进行融合,优势互补。

4. SSD系列中,DSSD在SSD的基础上,对深层特征图进行反卷积,与浅层的特征相乘,得到了更优的多层特征图,这对于小物体的检测十分有利。

5. RefineDet将SSD的多层特征图结构作为了Faster RCNN的RPN网络,结合了两者的优点。特征图处理上与FPN类似,利用反卷积与逐元素相加,将深层特征图与浅层的特征图进行结合,实现了一个十分精巧的检测网络。

6. YOLO系列中,YOLO v3也使用了特征融合的思想,通过上采样与通道拼接的方式,最终输出了3种尺寸的特征图。

5 SNIP:尺度归一化

论文地址:

https://arxiv.org/abs/1711.08189

代码地址:

https://github.com/mahyarnajibi/SNIPER

当前的物体检测算法通常使用微调的方法,即先在ImageNet数据集上训练分类任务,然后再迁移到物体检测的数据集上,如COCO来训练检测任务。我们可以将ImageNet的分类任务看做224×224的尺度,而COCO中的物体尺度大部分在几十像素的范围内,并且包含大量小物体,物体尺度差距更大,因此两者的样本差距太大,会导致映射迁移(Domain Shift)的误差。

SNIP是多尺度训练(Multi-Scale Training)的改进版本。MST的思想是使用随机采样的多分辨率图像使检测器具有尺度不变特性。然而作者通过实验发现,在MST中,对于极大目标和过小目标的检测效果并不好,但是MST也有一些优点,比如对一张图片会有几种不同分辨率,每个目标在训练时都会有几个不同的尺寸,那么总有一个尺寸在指定的尺寸范围内。

SNIP的做法是只对size在指定范围内的目标回传损失,即训练过程实际上只是针对某些特定目标进行,这样就能减少domain-shift带来的影响。

SNIP的网络结构如下图所示:

具体的实现细节

(1)3个尺度分别拥有各自的RPN模块,并且各自预测指定范围内的物体。

(2)对于大尺度的特征图,其RPN只负责预测被放大的小物体,对于小尺度的特征图,其RPN只负责预测被缩小的大物体,这样真实的物体尺度分布在较小的区间内,避免了极大或者极小的物体。

(3)在RPN阶段,如果真实物体不在该RPN预测范围内,会被判定为无效,并且与该无效物体的IoU大于0.3的Anchor也被判定为无效的Anchor。

(4)在训练时,只对有效的Proposal进行反向传播。在测试阶段,对有效的预测Boxes先缩放到原图尺度,利用Soft NMS将不同分辨率的预测结果合并。

(5)实现时SNIP采用了可变形卷积的卷积方式,并且为了降低对于GPU的占用,将原图随机裁剪为1000×1000大小的图像。

总体来说,SNIP让模型更专注于物体本身的检测,剥离了多尺度的学习难题。在网络搭建时,SNIP也使用了类似于MST的多尺度训练方法,构建了3个尺度的图像金字塔,但在训练时,只对指定范围内的Proposal进行反向传播,而忽略掉过大或者过小的Proposal。

SNIP方法虽然实现简单,但其背后却蕴藏深意,更深入地分析了当前检测算法在多尺度检测上的问题所在,在训练时只选择在一定尺度范围内的物体进行学习,在COCO数据集上有3%的检测精度提升,可谓是大道至简。

6 TridentNet:三叉戟网络

论文地址:

https://arxiv.org/abs/1901.01892

代码地址:

https://github.com/TuSimple/simpledet/tree/master/models/tridentnet

传统的解决多尺度检测的算法,大都依赖于图像金字塔与特征金字塔。与上述算法不同,图森组对感受野这一因素进行了深入的分析,并利用了空洞卷积这一利器,构建了简单的三分支网络TridentNet,对于多尺度物体的检测有了明显的精度提升。

TridentNet网络的作者将3种不同的感受野网络并行化,提出了如下图所示的检测框架。采用ResNet作为基础Backbone,前三个stage沿用原始的结构,在第四个stage,使用了三个感受野不同的并行网络。

具体实现细节

(1)3个不同的分支使用了空洞数不同的空洞卷积,感受野由小到大,可以更好地覆盖多尺度的物体分布。

(2)由于3个分支要检测的内容是相同的、要学习的特征也是相同的,只不过是形成了不同的感受野来检测不同尺度的物体,因此,3个分支共享权重,这样既充分利用了样本信息,学习到更本质的目标检测信息,也减少了参数量与过拟合的风险。

(3)借鉴了SNIP的思想,在每一个分支内只训练一定范围内的样本,避免了过大与过小的样本对于网络参数的影响。

在训练时,TridentNet网络的三个分支会接入三个不同的head网络进行后续损失计算。在测试时,由于没有先验的标签来选择不同的分支,因此只保留了一个分支进行前向计算,这种前向方法只有少量的精度损失。


http://chatgpt.dhexx.cn/article/xfKvCspO.shtml

相关文章

【笔记】多尺度方法

1.定义 2.常用架构 2.1多尺度输入网络 2.2 多尺度特征融合网络 (1) 并行多分支结构 (2) 串行多分支结构 2.3 多尺度特征预测融合 2.4 多尺度特征和预测融合 3.具体方法 3.1 SNIP 3.2 SNIPER(SNIP的改进) 3.3 SSD 3.4 TridentNet(…

多尺度多目标检测之金字塔

在日常学习工作中,经常会碰到一个概念,那就是金字塔(pyramid),本文就该概念进行一定的阐述,具体如下: (1)图像金字塔 图像金字塔结构,即对图像进行一定比例…

多尺度结构元素形态学边缘检测算法的研究-含Matlab代码

目录 一、引言二、数学形态学理论概述三、实验验证四、参考文献五、Matlab代码获取 一、引言 使用数字图像处理技术来解决计算机视觉、人工智能、生物遥感器视觉等领域所涉及到的图像问题时,最重要、最关键的一步是提取出图像中最有效、最有用的特征信息。而图像边…

多尺度熵---Understanding Multiscale Entropy

目录 导言计算多尺度熵多尺度熵在脑电分析中的应用参考文献 导言 多尺度熵(Multiscale entropy, MSE)将样本熵扩展到多个时间尺度,以便在时间尺度不确定时提供额外的观察视角。样本熵的问题在于它没有很好地考虑到时间序列中可能存在的不同时…

多尺度排列熵

文章目录 前言一、什么是多尺度排列熵?二、实验平台照片三、MATLAB代码3.1 多尺度排列熵3.2 排列熵 参考文献 前言 齿轮及齿轮箱作为机械设备常用的调节转速和传递转矩的旋转机械设备,不仅能够传递较大的功率和载荷,而且具有较好的可靠性。但…

多尺度是什么计算机视觉中 multi_SCALE

先给出定义吓死你们哈哈 多尺度,实际上就是对信号的 不同粒度 的采样 别急哈哈 粒度小,说明是一个很密集的采样,能看到更多更多的细节 而粒度粗 大 说明是一个很稀疏的采样,但是点与点之间隔得远了,就容易看到趋势了…

多尺度(multi-scale)目标检测方法

文章目录 1、多尺度图像预测2、金字塔特征预测2.1 FPN2.2 SSD 3、bounding box设计 1、多尺度图像预测 将图片进行不同尺度的缩放,得到图像金字塔,然后对每层图片提取不同尺度的特征,得到特征图。最后对每个尺度的特征都进行单独的预测。 特…

多尺度与多分辨率的理解

我一开始以为 多尺度与多分辨率 是一样的意思。后来看到了xiaowei_cqu博客的一篇文章“【OpenCV】SIFT原理与源码分析:DoG尺度空间构造”(以下简称,xiaowei一文),才发现我的理解有误。 尺度空间(scale space)理论 …

多尺度深度特征(上):多尺度特征学习才是目标检测精髓(干货满满,建议收藏)...

计算机视觉研究院专栏 作者:Edison_G 深度特征学习方案将重点从具有细节的具体特征转移到具有语义信息的抽象特征。它通过构建多尺度深度特征学习网络 (MDFN) 不仅考虑单个对象和局部上下文,还考虑它们之间的关系。 公众号ID|ComputerVisionG…

计算机视觉CV领域中多尺度特征的概念

知乎:深度学习中的多尺度模型设计 知乎:计算机视觉中的多尺度模型都有哪些设计? CSDN:多尺度理解 什么是多尺度? 所谓多尺度,实际就是对信号的不同粒度的采样。 通常在不同的尺度下我们可以观察到不同…

收藏吧 少年

程序员珍藏的东西会是什么?呵呵,除了平时写的代码,就是那些百看不厌的电子书了。 昨天很郁闷,我用了5年的移动硬盘,莫名奇妙的坏掉了。里面40G的资料全部报销了。 为了不再重蹈覆辙,我决定把重要的电子书…

一个程序员的多年珍藏--收藏

2010 - 01 - 15 [置顶] 一个程序员的多年珍藏(1月23日最新更新) 文章分类:Java编程 程序员珍藏的东西会是什么?呵呵,除了平时写的代码,就是那些百看不厌的电子书了。 昨天很郁闷,我用了5年的移动硬盘,莫名奇妙的坏掉了…

一个程序员多年的收藏

程序员珍藏的东西会是什么?呵呵,除了平时写的代码,就是那些百看不厌的电子书了。 昨天很郁闷,我用了5年的移动硬盘,莫名奇妙的坏掉了。里面40G的资料全部报销了。 为了不再重蹈覆辙,我决定把重要的电子书都…

转的一杂谈

网站架构(页面静态化,图片服务器分离,负载均衡)方案全解析 文章分类:综合技术 1、HTML静态化其实大家都知道,效率最高、消耗最小的就是纯静态化的html页面,所以我们尽可能使我们的网站上的页面采用静态页面来实现&…

PHP面试题(一)

1.用php打印前一天的时间,格式是2018-01-01 08:00:00? $adate("Y-m-d H:i:s",strtotime("-1 day"));print_r($a) 2.echo、print_r、print、var_dump的区别? echo、print是php语句,var_dump和print_r是函数…

Java高级必备

一、ES篇 1、概述 特点功能场景竞品分析对比 2、基本概念 IK分词器索引(类数据库)映射(类表设计)文档(数据) 3、高级特性 映射高级 地理坐标点数据类型动态映射 DSL高级聚合分析智能搜索 4、实战 写优化读优…

靠着这Java面试210题,成功拿下了10多家国内知名大厂Offer,10万字精华全部分享给大家

写在前面 我坚信,机会永远属于有准备的人,我们与其羡慕他人的成功,不如从此刻起,积累足够多的知识和面试经验,为将来进入更好的公司做好充分的准备! 如何让面试官在短短的几十分钟内认可你的能力? 如何在最短的时间内收获Java技术栈最核心的知识点 这份内容可以算是呕心沥血…

笔记总结备份

目录 文章目录 目录前言版本控制常用git 命令 操作系统系统机器数时间管理早期的 Linux 时间系统 中断内存管理内存分区malloc申请一块内存的背后原理RTOS 系统栈和协议栈寄存器磁盘调度算法虚拟内存页面置换算法分段段页式 Volatile(可见性)Atomic &…

MySQL常见面试题总结

MySQL常见面试题总结5---性能优化 单表优化设计字段索引查询SQL:充分利用索引,减少IO和全表扫描引擎事务锁定表使用外键Java方面 读写分离缓存批量读取和延迟修改分库分表垂直拆分水平拆分表分区 分库分表导致的问题事务一致性问题(见分布式事…

Java并发编程实战_盖兹

文章目录 第一部分 基础知识第1章 简介1.1 并发简史1.2 线程的优势1.3 线程带来的风险1.4 线程无处不在(框架线程或类线程并发注意点) 第2章 线程安全性2.1 什么是线程安全性2.2 原子性2.3 加锁机制内置锁:Synchronized关键字可重入锁:获取锁的操作粒度是…