当前位置: 首页 > news >正文

关于 Unsafe 的一点认识与总结

关于 Unsafe 的一点认识与总结

环境:JDK1.8u202

背景与起源

在学习BlockingQueue的一些基础时,看到官方资料说所有的BlockingQueue都是线程安全的;

那么是怎么实现线程安全的?以[ArrayBlockingQueue]为例,查看其put方法

    public void put(E e) throws InterruptedException {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == items.length)
                notFull.await();
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }

通过代码可知,其通过ReentrantLock锁实现的同步操作;

那么ReentrantLock又是如何实现上锁功能的呢?看其实现:

    private final Sync sync;
    public void lock() {
        sync.lock();
    }
    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

通过代码可知,ReentrantLock获取锁的底层实现是通过其内部类Sync来实现的;
关于Sync,看一下其实现:

    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * Performs {@link Lock#lock}. The main reason for subclassing
         * is to allow fast path for nonfair version.
         */
        abstract void lock();

        /**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

        protected final boolean isHeldExclusively() {
            // While we must in general read state before owner,
            // we don't need to do so to check if current thread is owner
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        // Methods relayed from outer class

        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }

        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }

        final boolean isLocked() {
            return getState() != 0;
        }

        /**
         * Reconstitutes the instance from a stream (that is, deserializes it).
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

可知Sync是继承自AbstractQueuedSynchronizer的一个实现类,而AbstractQueuedSynchronizer即AQS、队列同步器,它是构建锁或者其他同步组件的基础框架。

那么在 AQS 里又是如何实现线程同步的呢?

查看AbstractQueuedSynchronizer的源码,可以发现其使用到了UnsafeCAS操作,至于是怎么配合内部类Node来实现线程同步的,还需要细细研究(其实是水平有限)。

    private static final Unsafe unsafe = Unsafe.getUnsafe();

    // ...略...

    private static final boolean compareAndSetWaitStatus(Node node,
                                                         int expect,
                                                         int update) {
        return unsafe.compareAndSwapInt(node, waitStatusOffset,
                                        expect, update);
    }

    private static final boolean compareAndSetNext(Node node,
                                                   Node expect,
                                                   Node update) {
        return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
    }

至于Unsafe类的源码并未在OracleJDK中给出,我们可以在openJDK中参考其源码实现,openJDK如何查看请参考这里。

找到Unsafe类的源码在openJDK中位置:

./openjdk/jdk/src/share/classes/sun/misc/Unsafe.java
./openjdk/hotspot/src/share/vm/prims/unsafe.cpp

看过Unsafe.java源码的实现,会发现其中的方法大多都是native修饰的方法;

    /**
     * Atomically update Java variable to <tt>x</tt> if it is currently
     * holding <tt>expected</tt>.
     * @return <tt>true</tt> if successful
     */
    public final native boolean compareAndSwapObject(Object o, long offset,
                                                     Object expected,
                                                     Object x);

    /**
     * Atomically update Java variable to <tt>x</tt> if it is currently
     * holding <tt>expected</tt>.
     * @return <tt>true</tt> if successful
     */
    public final native boolean compareAndSwapInt(Object o, long offset,
                                                  int expected,
                                                  int x);

    /**
     * Atomically update Java variable to <tt>x</tt> if it is currently
     * holding <tt>expected</tt>.
     * @return <tt>true</tt> if successful
     */
    public final native boolean compareAndSwapLong(Object o, long offset,
                                                   long expected,
                                                   long x);

即底层都是C++实现,只能看unsafe.cpp的实现了。

// JSR166 ------------------------------------------------------------------

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h))
  UnsafeWrapper("Unsafe_CompareAndSwapObject");
  oop x = JNIHandles::resolve(x_h);
  oop e = JNIHandles::resolve(e_h);
  oop p = JNIHandles::resolve(obj);
  HeapWord* addr = (HeapWord *)index_oop_from_field_offset_long(p, offset);
  oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e, true);
  jboolean success  = (res == e);
  if (success)
    update_barrier_set((void*)addr, x);
  return success;
UNSAFE_END

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint 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;
UNSAFE_END

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong e, jlong x))
  UnsafeWrapper("Unsafe_CompareAndSwapLong");
  Handle p (THREAD, JNIHandles::resolve(obj));
  jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset));
  if (VM_Version::supports_cx8())
    return (jlong)(Atomic::cmpxchg(x, addr, e)) == e;
  else {
    jboolean success = false;
    ObjectLocker ol(p, THREAD);
    if (*addr == e) { *addr = x; success = true; }
    return success;
  }
UNSAFE_END

说实话,看不懂。。。

相关文章:

  • Apache服务器虚拟主机设置技术深入解析
  • 转载文章:在Spring Boot中使用条件化的Bean
  • 《赢在用户》8月19日北京书友会报道!
  • kryo浅析
  • 六招彻底防范ARP病毒反复发作
  • 转载:面试前必须要知道的Redis面试题
  • 如何检测网内IP地址是否被占用
  • 转载:Java并发编程-原子类实现
  • Java 中的四种引用类型
  • 美国国家安全局在监视全球网民?
  • 评论:微软的SOA战略
  • SpringBoot 以字符串格式传入时间
  • 基于JAVA的开源工作流引擎(Open Source Workflow Engines Written in Java)
  • SpringBoot WebFlux 官网文档阅读笔记
  • 拿到好牌就出昏招——郝玺龙妙语录
  • C# 免费离线人脸识别 2.0 Demo
  • conda常用的命令
  • express.js的介绍及使用
  • GitUp, 你不可错过的秀外慧中的git工具
  • HTTP 简介
  • If…else
  • IOS评论框不贴底(ios12新bug)
  • maya建模与骨骼动画快速实现人工鱼
  • ng6--错误信息小结(持续更新)
  • PHP那些事儿
  • Python十分钟制作属于你自己的个性logo
  • Sass 快速入门教程
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • vue 个人积累(使用工具,组件)
  • vue-router的history模式发布配置
  • Web设计流程优化:网页效果图设计新思路
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 前端每日实战:70# 视频演示如何用纯 CSS 创作一只徘徊的果冻怪兽
  • 入手阿里云新服务器的部署NODE
  • 为视图添加丝滑的水波纹
  • 要让cordova项目适配iphoneX + ios11.4,总共要几步?三步
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • #define,static,const,三种常量的区别
  • #鸿蒙生态创新中心#揭幕仪式在深圳湾科技生态园举行
  • $.ajax()
  • %@ page import=%的用法
  • (6)设计一个TimeMap
  • (C#)Windows Shell 外壳编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令...
  • (第二周)效能测试
  • (附源码)ssm考生评分系统 毕业设计 071114
  • (免费分享)基于springboot,vue疗养中心管理系统
  • (原創) 如何動態建立二維陣列(多維陣列)? (.NET) (C#)
  • ***利用Ms05002溢出找“肉鸡
  • .Net core 6.0 升8.0
  • .Net Core与存储过程(一)
  • .NET 应用启用与禁用自动生成绑定重定向 (bindingRedirect),解决不同版本 dll 的依赖问题
  • .NET高级面试指南专题十一【 设计模式介绍,为什么要用设计模式】
  • ??eclipse的安装配置问题!??
  • @Import注解详解
  • [Android Studio] 开发Java 程序