吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 610|回复: 1
收起左侧

[学习记录] volatile保证线程可见性和禁止指令重排序

[复制链接]
黑白客 发表于 2022-11-4 18:10

volatile保证线程可见性和禁止指令重排序
保证线程可见性
禁止指令重排序
单例模式
代码演示
双重锁
锁细化 锁粗化
volatile的使用
锁定的对象改变
CAS
atomic
ABA

保证线程可见性

使用了volatile之后,可以保证可见性,就是一个线程修改了,另一个线程能够立刻看到

可见性不是锁,并不能保证数据的安全,可能再同一个时间点,两个线程都看到了2,然后都去加1,本来是变成4.但是都是在2的基础上加的,所以变成了3

原理

禁止线程私有区域 :在jvm中,堆是线程共有区域,多个线程操作堆中的同一个数据时,比如要在1上进行加一,这个时候会把堆中的数据复制到线程的一块私有内存中,在私有内存中进行加1,然后将结果在复制到堆中

加上volatile关键字之后,就禁止了线程的私有内存空间,操作时直接在堆上操作,因此其它线程可以立即看到

类似于我们cpu之间的一致性,目前的多个cpu运行时,也需要保证缓存的一直性,用到了MESI 缓存一致性协议

禁止指令重排序

为什么会重排? 最早的cpu在运行指令时,是串行执行的,后来为了提高效率,cpu将多个指令并行运行,经过验证运行速度提高很大

我们平时的一行代码,到cpu那里可能会拆分为多个指令,
如: new Object();分为

  • 指定内存 (加载,验证和准备)
  • 赋初始值 (解析)
  • 将内存赋值给对象 (初始化 )
    正常操作时,没有问题,但是上面的指令,执行顺序可能是 132
    那么就会出现异常:
    当执行完 3 之后,我们的对象已经不是null了。如果我们的代码里有判断null的逻辑,就会认为这个对象已经初始化完成,然后直接使用,但是这个时候可能我们这个对象里的值还没有初始化,就会导致错误

i++ 也是不安全的 会拆分为多个指令

使用完volatile之后,会可以防止当前命令的所有指令重排
实现方式cpu有关
cpu会将指令并行执行,通过在所有指令的前后添加一下内容
loadfence 原语指令
storefence 原语指令

单例模式

代码演示

package 线程同步volatile;

/**
 * @program: solution
 * @description: 单例模式
 * @author: Wang Hai Xin
 * @create: 2022-11-03 18:34
 **/
public class T {
    public static volatile T t;
    public T init(){
        /*这里写init的其它逻辑*/

        /*双重锁*/
        if (t == null) {
            synchronized (T.class){
                if (t == null) {
                   t =  new T();
                }
            }
        }
       return t;
    }
}

双重锁

    if (t == null) {
        synchronized (T.class){
            if (t == null) {
               t =  new T();
            }
        }
    }

第一个判断是为了防止更多的线程被锁,
在synchronized中,加if判断,是为了多个被锁的线程,只有第一个会去创建,剩下的直接跳过

锁细化 锁粗化

这里可扩展一下的知识,锁细化和锁粗化,我们本来可以直接在方法上添加synchronized,但是在init方法中就锁住了很多其它的逻辑,我们通过在里面只锁定了创建对象的一行代码,就是典型的锁细化。

聊完锁细化,就可以聊聊锁粗化了,锁粗化和锁细化恰恰相反,加入我们需要加锁的代码很紧密,如果分别加锁,lock 和unlock也是很影响效率的,这个时候就可以用一个锁或者几个锁,把代码全部锁住,减少lock和unlock所需要的时间

volatile的使用

聊的有点远了,再撤回来,我们在  public static volatile T t;
上加了 volatile关键字,为什么加呢?
看了上面的 禁止指令重排序  你应该就理解了
我们在执行顺序132,导致if中判断时不为null。

锁定的对象改变

属性改变不影响锁
锁定的对象变成另一个对象就会影响锁,(锁信息写在对象头里)

锁只能保证在同一个classloade中生效,在多个classloade不能生效
内存可以自定义 classloade

CAS

Compare And Set
比较并且设定!

CAS被称为无锁优化

atomic

java中util包中有一个 atomic类,里面都是线程安全的
有 AtomicInteger
Atomxxx 类本身方法都是原子性的,但不能保证多个方法连续调用的原子性。
AtomicInteger代码演示如下

package 线程同步Atomic;

import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @program: solution
 * @description: integer的原子操作类,保证线程安全
 * @author: Wang Hai Xin
 * @create: 2022-11-04 11:28
 **/
public class To1AtomicInteger {
    AtomicInteger atomicInteger = new AtomicInteger(0);

    public static void main(String[] args) {
        To1AtomicInteger t = new To1AtomicInteger();
        ArrayList<Thread> threads = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
           threads.add( new Thread(t::m,"thread"+i));
        }

        threads.forEach((o)-> o.start());
        threads.forEach((o)->
                {
                    try {
                        /*join 让主线程等待子线程(一个线程内创建了另一个线程,创建的为主线程,被创建的为子线程)运行完毕,主线程再运行*/
                        o.join();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                );

        System.out.println(t.atomicInteger);
    }

    private void m() {
        for (int i = 0; i < 10; i++) {
            atomicInteger.incrementAndGet();//自增1
        }
    }

}

cas(object要改的值,期望改成值,要该成的值 )

当修改完成之后,判断要改的值有没有变,就是判断一下在修改的这段时间,有没有其它线程对数据进行写操作

cas在写操作少的时候,是可以提高效率的,但是如果线程过多,就会导致效率低下,因为当一个线程修改完之后,发现被其它线程修改了,就会重新读取再次修改,当竞争激烈时,会不停的重复这个动作

ABA

上面的cas操作,可能存在一个问题,假如线程1再修改A时,线程2 修改了线程A的某个属性,线程1回来时,发现还是A,以为没有被别的线程进行写操作,然后写入了,这个时候就会产生错误。

主要发生在引用类型上
解决办法

加版本号,通过版本号控制,比如没进来一个我们都加1 ,修改完毕 我们再判断这个数字是否改变

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

头像被屏蔽
xiadongming 发表于 2022-11-5 17:05
提示: 作者被禁止或删除 内容自动屏蔽
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 05:17

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表