java面试题之多线程

1谈谈 volatile 理解

volatile: 低配的同步锁,保障有序性(禁止指令重排,内存屏障),可见性(打小报告)
有序性是如何保证的:通过插入内存屏障,来禁止 屏障 之前与屏障之后的指令交换位置
可见性:

2谈谈CAS

含义,底层原理,Unsafe 类理解
CAS 缺点:

多线程环境下,对共享变量的操作,要么加锁,要么CAS

神马是CAS?
CAS 底层实现?
CAS 优缺点?
CAS ABA 问题?
如何解决?
原子引用?

CAS 含义以及的层代码实现(AtomicInteger 类)

加锁 :保证只能同时有一个线程去操作 数据
CAS:比较交换,偏量值 ,主要思想是通过读取主内存的值 和预期旧值比较,如果相同,则将新值=预期旧值+偏量值 写入主内存(如果写入失败,重新读取旧值)
经典的使用例子便是jdk 中的atomic 包(查看源码可以看见有乐观锁的思想)
以AtomicInteger 的 getAndIncrement() 方法为例

AtomicInteger atomicInteger=new AtomicInteger();
        atomicInteger.getAndIncrement();
        --/**
     * Atomically increments by one the current value.
     *
     * @return the previous value
     */
    public final int getAndIncrement() {
   
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }
    

Unsafe 类:


       /**
     * Atomically adds the given value to the current value of a field
     * or array element within the given object <code>o</code>
     * at the given <code>offset</code>.
     *
     * @param o object/array to update the field/element in
     * @param offset field/element offset
     * @param delta the value to add
     * @return the previous value
     * @since 1.8
     */
     // O 是指当前对象,或者说是首地址
     //offset 是指内存偏移量// delta 是指变化量
     
    public final int getAndAddInt(Object o, long offset, int delta) {
   
        int v;
        do {
   
        // 读取当前对象+offset 内存地址上的值
            v = getIntVolatile(o, offset);// 获取主内存值
        } while (!compareAndSwapInt(o, offset, v, v + delta));// 如果没有交换成功,重新读取主内存值,进行下一次交换,直到成功为止
        return v;
    }

compareAndSwapInt 的底层就是 c语言的实现了,位于unsafe.cpp 中

UNSAFE_ENTRY(jboolean,uNSAFE_cOMPAREaNDsWAPiNT(jnieNV *env,jobject unsafe,jlong offset,iint e,jint x))
UnsafeWrapper("Unsafe_CompareAndSwapInt");
oop p=JNIHandles::resolve(obj);// 对象首地址
jint * addr=(jint*) index_oop_from_field_offset_long(p,offset);// 对象的属性字段的地址
return (jint)(Atomic::cmpxchg(x,addr,e))==e;// 注意atomic 则保证此操作是原子性的不可中断的
UNSAFE_END

CAS=Compare and Swap CPU 并发原语(原子性)

CAS 优缺点

  1. 如果CAS 失败,会一直尝试CAS,空转,CPU开销
  2. 只能保证单个变量
  3. ABA 问题

ABA 问题

主内存:初始值 1
线程 A 和线程B 读取主内存 值 为自己工作空间(拷贝一份)
线程 在CAS 过程中 将数据从主内存获取(得到1)
线程A 将数据改为 改为2 并且完成刷回主内存
线程A 将数据改为1 并且完成刷回主内存
线程B 执行 CompareAndSwap 操作 将数据 更改为3(CAS 个会成功)
因为线程B 读取到的仍是1(虽然不是最初的那个1,中途被改变,线程B无法感知)

忽略了中间过程的变化,只注意了首尾状态

原子引用更新

Atomic 只是提供了 基本数据类型的原子操作
如果现在有User/Account 这些类型也需要原子操作呢?

class User{
   
    String name;
    int age;

    public User(String name, int age
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值