Unsafe 学习和源码阅读
在代码中获取 Unsafe 对象的方法:
// 在 AtomicInteger 里面是这么用的private static final Unsafe unsafe = Unsafe.getUnsafe();
// 获取内存的偏移地址,有点奇怪啊,为啥是获取这个类的,而不是这个对象的呢?static { try { valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); }}
1.8 之前 Unsafe 的包路径为:
package sun.misc;
而到了 Java 9,它的包路径改成了下面这个,说明这个类已经开放使用。
package jdk.internal.misc;
获取 Unsafe 对象,这个是 openjdk 里的方法,通过反射获得。
static { Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe");}
1)内存管理
可以分配内存了哦
public native long allocateMemory(long var1);
public native long reallocateMemory(long var1, long var3);
public native void setMemory(Object var1, long var2, long var4, byte var6);
2)CAS 乐观锁
如果变量没有被其他线程改变的话,会一直尝试去修改变量,直到变成修改值。
CAS,Compare and Swap 即比较并交换,设计并发算法时常用到的一种技术,java.util.concurrent 包全完建立在 CAS 之上,没有 CAS 也就没有此包,可见 CAS 的重要性。
当前的处理器基本都支持 CAS,只不过不同的厂家的实现不一样罢了。CAS 有三个操作数:内存值 V、旧的预期值 A、要修改的值 B,当且仅当预期值 A 和内存值 V 相同时,将内存值修改为 B 并返回 true,否则什么都不做并返回 false。
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
这里的参数是,对象,偏移量,期望值,修改值。
每次都是先去获取当前的值,然后再进行修改,所以如果有机会的话是一定会成功的。
获取偏移量的方法:
valueOffset = unsafe.objectFieldOffset(AtomicBoolean.class.getDeclaredField("value"));
还有:
public native long staticFieldOffset(Field var1);
public native long objectFieldOffset(Field var1);
public native Object staticFieldBase(Field var1);
3)supportlock
public native void unpark(Object var1);
public native void park(boolean var1, long var2);
park类似于wait,unpark类似于notify。
4)cas 源码分析
具体见 unsafe.cpp (版本:openjdk 9 )
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) { oop p = JNIHandles::resolve(obj); //获取对象的变量的地址 jint* addr = (jint *)index_oop_from_field_offset_long(p, offset); //调用Atomic操作 return (jint)(Atomic::cmpxchg(x, addr, e)) == e;} UNSAFE_END
进入 atomic.hpp,大意就是先去获取一次结果,如果结果和现在不同,就直接返回,因为有其他人修改了;否则会一直尝试去修改。直到成功。
inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value, cmpxchg_memory_order order) { STATIC_ASSERT(sizeof(jbyte) == 1); volatile jint* dest_int = static_cast<volatile jint*>(align_ptr_down(dest, sizeof(jint))); size_t offset = pointer_delta(dest, dest_int, 1); jint cur = *dest_int; jbyte* cur_as_bytes = reinterpret_cast<jbyte*>(&cur); // current value may not be what we are looking for, so force it // to that value so the initial cmpxchg will fail if it is different cur_as_bytes[offset] = compare_value; // always execute a real cmpxchg so that we get the required memory // barriers even on initial failure do { // value to swap in matches current value ... jint new_value = cur; // ... except for the one jbyte we want to update reinterpret_cast<jbyte*>(&new_value)[offset] = exchange_value; jint res = cmpxchg(new_value, dest_int, cur, order); if (res == cur) break; // success // at least one jbyte in the jint changed value, so update // our view of the current jint cur = res; // if our jbyte is still as cur we loop and try again } while (cur_as_bytes[offset] == compare_value); return cur_as_bytes[offset];}
5)CAS的缺点
CAS 看起来很美,但这种操作显然无法涵盖并发下的所有场景,并且 CAS 从语义上来说也不是完美的,存在这样一个逻辑漏洞:如果一个变量 V 初次读取的时候是 A 值,并且在准备赋值的时候检查到它仍然是 A 值,那我们就能说明它的值没有被其他线程修改过了吗?如果在这段期间它的值曾经被改成了 B,然后又改回 A,那 CAS 操作就会误认为它从来没有被修改过。这个漏洞称为 CAS 操作的 "ABA" 问题。java.util.concurrent 包为了解决这个问题,提供了一个带有标记的原子引用类 "AtomicStampedReference",它可以通过控制变量值的版本来保证 CAS 的正确性。不过目前来说这个类比较 "鸡肋",大部分情况下 ABA 问题并不会影响程序并发的正确性,如果需要解决 ABA 问题,使用传统的互斥同步可能回避原子类更加高效。
Unsafe 学习和源码阅读的更多相关文章
- Dapper源码学习和源码修改
之前ORM比较火热,自己也搞了个WangSql,但是感觉比较low,大家都说Dapper性能好,所以现在学习学习Dapper,下面简单从宏观层面讲讲我学习的Dapper. 再了解一个东西前,先得学会使 ...
- Dapper源码学习和源码修改(下篇)
目录: Dapper源码学习和源码修改(上篇主要讲解入参解析) Dapper源码学习和源码修改(下篇主要讲解出参解析) 继上篇讲了下自己学习Dapper的心得之后,下篇也随之而来,上篇主要讲的入参解析 ...
- Spring的学习和源码的学习
PS:Spring中有各种的Templeate,比如jdncTemplate,主要是为了避免各种模板的代码,抽象出来的 PS: @Configration.@Bean是用来替代xml那种解析方式 PS ...
- 以CapsNet为例谈深度学习源码阅读
本文的参考的github工程链接:https://github.com/laubonghaudoi/CapsNet_guide_PyTorch 之前是看过一些深度学习的代码,但是没有养成良好的阅读规范 ...
- SpringMVC源码阅读:过滤器
1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...
- SpringMVC源码阅读:属性编辑器、数据绑定
1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...
- SpringMVC源码阅读:拦截器
1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...
- SpringMVC源码阅读:核心分发器DispatcherServlet
1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将介绍SpringMVC的核 ...
- SpringMVC源码阅读:定位Controller
1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码分析,弄清楚Spr ...
随机推荐
- Linux shell中处理
awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息 awk处理过程: 依次对每一行进行处理,然后输出 awk命令形式: awk ...
- Java中设置方法执行的超时时间java.util.concurrent.Future
java.util.concurrent.Future Future代表一个异步计算的结果.它提供了方法来检查是否计算已经完成,还是正在计算而处于等待状态,并且也提供了获取计算结果 方法.当计算完成后 ...
- 使用windows脚本移动文件
1. 移动脚本 在部署web项目时,一般需要将打包的war包发布到Tomcat目录下,所以自己就在网上查找资料写了一个简略的移动文件的脚本,如下: @echo off echo "使用bat ...
- SQL 查询存储过程
select distinct name from syscomments a,sysobjects b where a.id=b.id and b.xtype='p' --and text like ...
- 极客无极限 一行HTML5代码引发的创意大爆炸
摘要:一行HTML5代码能做什么?国外开发者Jose Jesus Perez Aguinaga写了一行HTML5代码的文本编辑器.这件事在分享到Code Wall.Hacker News之后,引起了众 ...
- Bootstrap 分页、标签、徽章、超大屏幕、页面标题
分页(pagination), 是一种无序列表 1.默认的分页(.pagination) 代码示例: <ul class="pagination"> <li> ...
- loj#2054. 「TJOI / HEOI2016」树
题目链接 loj#2054. 「TJOI / HEOI2016」树 题解 每次标记覆盖整棵字数,子树维护对于标记深度取max dfs序+线段树维护一下 代码 #include<cstdio> ...
- [CF490F]Treeland Tour(线段树合并)
树上LIS:树上找一条简单路径的子序列使点权严格单增,最大化长度. 原题数据过小,用线段树合并可以做到$O(n\log n)$. 每个点用一棵线段树维护以每个权值为结尾的LIS最长长度,线段树合并时更 ...
- BZOJ.3585.mex(线段树)
题目链接 题意:多次求区间\(mex\). 考虑\([1,i]\)的\(mex[i]\),显然是单调的 而对于\([l,r]\)与\([l+1,r]\),如果\(nxt[a[l]]>r\),那么 ...
- BZOJ4714 : 旋转排列
对于每个$k$,问题等价于求有多少置换满足: 1.存在一个循环长度为$k$ 2.任意一个循环长度$\geq 2$ 枚举这种环的个数$t$: 设$g_t$表示至少有$kt$个人分成$t$个长度为$k$的 ...