首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UNSAFE.compareAndSwapObject到底是做什么的

UNSAFE.compareAndSwapObject到底是做什么的
EN

Stack Overflow用户
提问于 2014-02-27 17:36:55
回答 1查看 3.5K关注 0票数 9

我发现UNSAFE.compareAndSwapObject在阅读JDK ConcurrentLinkedQueue时非常奇怪。( CLQ类是从ConcurrentLinkedQueue复制的,以便于调试.)

当我向ConcurrentLinkedQueue提供第一项时。

  • p.casNext(null, newNode) head==tail==p==t之前引用相同的对象,如下所示。 http://i.stack.imgur.com/8dCO0.png
  • 进入casNext后的UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val); 按照预期,p.next将引用到newNode,如下所示。 http://i.stack.imgur.com/mNtUN.png
  • 站出来提供 一切都变得奇怪..。我能理解为什么p.next裁判伤口会变成p,头部裁判newNode怎么会自动. http://i.stack.imgur.com/Pvvcy.png

代码: ConcurrentLinkedQueue.class ()

代码语言:javascript
复制
public boolean offer(E e) {
    checkNotNull(e);
    final Node<E> newNode = new Node<E>(e);

    for (Node<E> t = tail, p = t;;) {
        Node<E> q = p.next;
        if (q == null) {
            // p is last node
            if (p.casNext(null, newNode)) {
                // Successful CAS is the linearization point
                // for e to become an element of this queue,
                // and for newNode to become "live".
                if (p != t) // hop two nodes at a time
                    casTail(t, newNode);  // Failure is OK.
                return true;
            }
            // Lost CAS race to another thread; re-read next
        }
        else if (p == q)
            // We have fallen off list.  If tail is unchanged, it
            // will also be off-list, in which case we need to
            // jump to head, from which all live nodes are always
            // reachable.  Else the new tail is a better bet.
            p = (t != (t = tail)) ? t : head;
        else
            // Check for tail updates after two hops.
            p = (p != t && t != (t = tail)) ? t : q;
    }
}
EN

回答 1

Stack Overflow用户

发布于 2022-11-12 08:19:31

它的操作可能类似于下面的伪代码,但是用所谓的本机代码(C/C++)编写,通常比Java快得多:

代码语言:javascript
复制
boolean compareAndSwapObject(Object obj, long fieldId, Object expectedValue, Object newValue) {
    synchronized (globalExchangeLock) {
        if (obj.fieldArray.get(fieldId) == expectedValue) {
            obj.fieldArray.set(fieldId, newValue);
            return true;
        }
    }
    return false;
}

private static final Object globalExchangeLock = new Object();

然而,传递fieldId并不复杂,可能应该缓存,就像下面的Java代码(这次不是伪代码):

代码语言:javascript
复制
public class MyClass {
    int myField;

    // ...

    private static final sun.misc.Unsafe U = UnsafeAcc.unsafe;
    private static final long MY_FIELD_ID;

    static {
        try {
            MY_FIELD_ID = U.objectFieldOffset(
                MyClass.class.getDeclaredField("myField")
            );
        } catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }
}

在我的Android项目中使用:

代码语言:javascript
复制
/*
 * Written by Stefan Zobel and released to the
 * public domain, as explained at
 * http://creativecommons.org/publicdomain/zero/1.0/
 */
package java8.util.concurrent;

import java.lang.reflect.Field;

import sun.misc.Unsafe;

final class UnsafeAcc {

    static final Unsafe unsafe;

    static {
        try {
            Field field = null;
            try {
                field = Unsafe.class.getDeclaredField("theUnsafe");
            } catch (NoSuchFieldException ignored) {
                // For older Androids.
                field = Unsafe.class.getDeclaredField("THE_ONE");
            }
            field.setAccessible(true);
            unsafe = (Unsafe) field.get(null);
        } catch (Exception e) {
            throw new Error(e);
        }
    }

    private UnsafeAcc() {
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22076083

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档