关于volatile关键字

本文详细解析了Java中volatile关键字的作用机制,包括其如何确保多线程环境下变量的可见性,以及为何不能保证原子性等问题。

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

作用

关键字volatile的主要作用是使变量在多个线程间可见

举个例子:

class RunThread extends Thread {
    private boolean isRunning = true;
    public boolean isRunning() {
        return isRunning;
    }

    public void setRunning(boolean running) {
        isRunning = running;
    }

    @Override
    public void run() {
        System.out.println("进入run了");
        while (isRunning == true) {

        }
        System.out.println("线程被停止了");
    }
}
public class Demo3 {
    public static void main(String[] args) {
        RunThread runThread = new RunThread();
        runThread.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        runThread.setRunning(false);
        System.out.println("已经赋值为false");
    }

}

在这里插入图片描述
上述代码执行结果中,线程被停止这句话一直没有出现。

而给变量加上关键字volatile后:

class RunThread extends Thread {
    volatile private boolean isRunning = true;
    public boolean isRunning() {
        return isRunning;
    }

    public void setRunning(boolean running) {
        isRunning = running;
    }

    @Override
    public void run() {
        System.out.println("进入run了");
        while (isRunning == true) {

        }
        System.out.println("线程被停止了");
    }
}
public class Demo3 {
    public static void main(String[] args) {
        RunThread runThread = new RunThread();
        runThread.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        runThread.setRunning(false);
        System.out.println("已经赋值为false");
    }

}

在这里插入图片描述
则结果就明显不一样了,原因就是在runThread启动时,变量private boolean isRunning = true存在于公共堆栈及线程的私有堆栈中,在JVM被设置为-server模式时,为了线程运行的效率,线程一直在私有堆栈中取得isRunning的值是true,而代码thread.setRunning(false);虽然执行,更新的是公共堆栈中的isRunning变量值false,所以一直就是死循环状态,volatile关键字的作用就是强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量值。

这个是线程私有堆栈模型:

在这里插入图片描述

线程公共内存模型:
在这里插入图片描述

缺点

volatile关键字最致命的缺点是不支持原子性。

比较synchronized和volatile:
1.volatile是线程同步的轻量级实现,他只能修饰变量,而synchronized可以修饰方法以及代码块。
2.多线程访问volatile不会发生阻塞,而synchronized会。
3.volatile可以保证数据的可见性,但不能保证原子性,而synchronized可以保证原子性,间接也可以保证可见性,因为他会将私有内存和公共内存中的数据做同步。
4.volatile解决的是变量在多个线程之间的可见性,而synchronized关键字解决的是多个线程之间访问资源的同步性。

线程安全包含原子性和可见性两方面,Java同步机制都是围绕这两个方面来确保线程的安全的。

同时还需要注意一个点,就是在对有volatile关键字修饰的变量做一些操作时,比如对他进行加加操作,例如i++,这操作并不是一个原子操作,它分为:
1.从内存中取出i的值
2.计算i的值
3.将i写入内存中
假设计算第二步时,另一个线程也修改i的值,那么这个时候就会出现脏数据,解决办法就是加上synchronized关键字,所以volatile这个关键字本身并不处理原子性。

下面用图演示一下volatile关键字出现非线程安全原因。

在这里插入图片描述
1.read,load阶段:从主存赋值变量到当前线程工作内存
2.use,assign阶段:执行代码,改变共享变量值
3.store,write阶段:用工作内存数据刷新主存对应变量的值

对于volatile修饰的变量,JVM虚拟机只是保证从主存加载到线程工作内存的值是最新的,也就是volatile关键字解决的是变量读时的可见性问题,但无法保证原子性,对于多个线程访问同一个实例变量还是需要加锁同步。

### Swin Transformer 论文精读:Hierarchical Vision Transformer Using Shifted Windows Swin Transformer 是一种基于视觉的分层 Transformer 模型,其核心创新在于通过 **Shifted Window-based Self-Attention** 实现了线性计算复杂度,同时能够生成多尺度特征表示。这种方法在图像分类、目标检测和语义分割等任务中取得了显著的性能提升 [^2]。 #### 核心架构概述 Swin Transformer 的整体结构分为多个阶段(Stage),每个阶段包含多个 Swin Transformer Block。这些块使用 **窗口化自注意力机制** 和 **移位窗口策略** 来实现高效计算并捕捉长距离依赖关系。 - **分层特征提取** 类似于传统卷积神经网络(如 ResNet),Swin Transformer 采用分层设计来逐步降低空间分辨率并增加通道维度。这种设计允许模型从局部到全局地构建特征表示。 - **窗口划分与移位窗口机制** 在每个 Swin Transformer Block 中,输入特征图被划分为不重叠的窗口,并在这些窗口内执行自注意力计算。为了增强跨窗口的信息交互,在下一个 Block 中对窗口进行移位操作(Shifted Windows)。这种方式既减少了计算量,又保持了模型对全局信息的感知能力 [^1]。 ```python # 窗口划分伪代码示例 def window_partition(x, window_size): B, H, W, C = x.shape # 将图像划分为多个窗口 x = tf.reshape(x, shape=[B, H // window_size, window_size, W // window_size, window_size, C]) windows = tf.transpose(x, perm=[0, 1, 3, 2, 4, 5]) return tf.reshape(windows, shape=[-1, window_size, window_size, C]) # 移位窗口伪代码 def shifted_window_attention(x, window_size, shift_size): B, H, W, C = x.shape # 对特征图进行滚动操作以实现窗口移位 x = tf.roll(x, shift=(-shift_size, -shift_size), axis=(1, 2)) return window_partition(x, window_size) ``` #### 自注意力机制优化 传统的 Vision TransformerViT)在整个图像上应用自注意力机制,导致计算复杂度为 $O(n^2)$,其中 $n$ 是图像块的数量。而 Swin Transformer 通过将注意力限制在局部窗口内,将复杂度降低到 $O(n)$,使其适用于高分辨率图像处理 [^4]。 此外,移位窗口机制确保了相邻窗口之间的信息流动,从而避免了局部注意力带来的信息隔离问题。这种设计使得 Swin Transformer 能够在保持计算效率的同时实现全局建模能力。 #### 实验结果与性能优势 Swin Transformer 在多个视觉任务中表现出色: - **ImageNet 分类任务**:Swin-Tiny、Swin-Small、Swin-Base 和 Swin-Large 四种变体均在 ImageNet-1K 上实现了优于其他 Transformer 主干网络的 Top-1 准确率。 - **COCO 目标检测**:在 COCO 数据集上,Swin Transformer 在 Faster R-CNN 框架下达到了 SOTA 性能,mAP 超过之前的最佳方法。 - **ADE20K 语义分割**:在 ADE20K 数据集上,Swin Transformer 作为编码器也取得了领先的 mIoU 指标 [^2]。 #### 消融实验分析 论文还进行了详细的消融研究,验证了以下几个关键组件的有效性: - **窗口大小的影响**:较大的窗口有助于捕捉更广泛的上下文,但会增加计算开销。 - **移位窗口的重要性**:实验证明,移位机制可以显著提升模型性能,尤其是在长距离依赖任务中。 - **不同层级的设计**:通过对比不同层级深度和通道配置,论文展示了如何平衡精度与效率 [^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lhj_loveFang_1105

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值