java.util.concurrent各组件分析 一 sun.misc.Unsafe

说到concurrent包也叫并发包,该包下主要是线程操作,方便的进行并发编程,提到并发那么锁自然是不可缺少的,包中的类存在了大量关于锁的操作

因此有必要先了解java中锁的原理,锁的底层就是sun.misc.Unsafe类,这个类可以说是java并发包的基础,基本上并发包的所有组件都是依赖Unsafe来进行底层同步操作的

java不能直接访问操作系统底层,而是通过本地方法来访问,Unsafe类提供了硬件级别的原子操作,在100+的方法中大部分都是native类型的,可以进行底层操作,
比如操作内存、低级同步、CAS方法、操作Class、操作Object等等。实际通过该类就像C、C++一样可以精确操作内存。

但java特点就是面向对象,表面上是不进行类似指针形式的直接内存操作,因此该类是不提倡我们在上层的代码中直接使用的。

1.简单知道可以操作内存
类中有3个本地方法allocateMemory、reallocateMemory、freeMemory分别用于分配内存,扩充内存和释放内存,与C语言中的3个方法是对应的。
再深入就追踪到C的类库中了,不向下看了。

2.与并发编程相关的几类方法
2.1 CAS方法
2.2 通过getBooleanVolatile等方法,定位字段,进行存取
2.2 操作线程的方法,park线程等待,unpark唤醒线程

2.3 CAS方法,主要是compareAndSwapXXX方法
compareAndSwapObject提供了对一个对象引用进行CAS的能力
compareAndSwapInt提供了对一个32位整数进行CAS操作的能力
compareAndSwapLong提供了对64位整数进行CAS操作的能力

	/**
* 比较obj的offset处内存位置中的值和期望的值,如果相同则更新。此更新是不可中断的。
*
* @param obj 需要更新的对象
* @param offset obj中整型field的偏移量
* @param expect 希望field中存在的值
* @param update 如果期望值expect与field的当前值相同,设置filed的值为这个新值
* @return 如果field的值被更改返回true
*/
public native boolean compareAndSwapInt(Object obj, long offset, int expect, int update);

 

CAS操作看起来是很爽的,但是CAS操作会存在ABA问题,简单来说就是某线程进行compareAndSwap,在进行比较时,另一个线程对该内存值进行了两次或以上的更新操作,
但最终还原了值,这时对前一个线程来说相当于没变CAS操作成功。但是这个成功不代表没问题,如果值是对象、链表等其中的属性或某种状态是发生了变化的就有问题了。
解决ABA问题可以使用AtomicStampedReference/AtomicMarkableReference类进行,其带有数据版本号完全避免了ABA问题

2.2 通过getBooleanVolatile等方法,定位字段,进行存取

1.获取内存位置有staticFieldOffset、objectFieldOffset方法实现,方法返回给定field的内存地址偏移量,这个值对于给定的filed是唯一的且是固定不变的。

2.还可以通过下面的一系列,获取内存地址的方法

public native void putObjectVolatile(Object var1, long var2, Object var4);

    public native int getIntVolatile(Object var1, long var2);

    public native void putIntVolatile(Object var1, long var2, int var4);

    public native boolean getBooleanVolatile(Object var1, long var2);

    public native void putBooleanVolatile(Object var1, long var2, boolean var4);

    public native byte getByteVolatile(Object var1, long var2);

    public native void putByteVolatile(Object var1, long var2, byte var4);

    public native short getShortVolatile(Object var1, long var2);

    public native void putShortVolatile(Object var1, long var2, short var4);

    public native char getCharVolatile(Object var1, long var2);

    public native void putCharVolatile(Object var1, long var2, char var4);

    public native long getLongVolatile(Object var1, long var2);

    public native void putLongVolatile(Object var1, long var2, long var4);

    public native float getFloatVolatile(Object var1, long var2);

    public native void putFloatVolatile(Object var1, long var2, float var4);

    public native double getDoubleVolatile(Object var1, long var2);

    public native void putDoubleVolatile(Object var1, long var2, double var4);

    public native void putOrderedObject(Object var1, long var2, Object var4);

    public native void putOrderedInt(Object var1, long var2, int var4);

    public native void putOrderedLong(Object var1, long var2, long var4);

3.数组类型有BASE_OFFSET结尾的这些常量辅助去找位置
public static final int ARRAY_BOOLEAN_BASE_OFFSET;
public static final int ARRAY_BYTE_BASE_OFFSET;
public static final int ARRAY_SHORT_BASE_OFFSET;
public static final int ARRAY_CHAR_BASE_OFFSET;

2.3 操作线程的方法,park线程等待,unpark唤醒线程
park 让线程进入等待,并释放锁。调用后线程将一直阻塞知道超时或中断等条件出现。
unpark 唤醒等待的线程使其恢复正常。

在使用Unsafe时,我们需要Unsafe对象的实例。但Unsafe unsafe = new Unsafe()是不行的,其构造方法是私有的,它也有一个静态的getUnsafe()方法,
但如果直接调用Unsafe.getUnsafe(),会报SecurityException异常,只能从受信任的代码中使用这个方法。
这个受信任就比较麻烦,但Unsafe类包含一个私有的、名为theUnsafe的实例,可以通过Java反射等窃取该变量。
说这么多我们就会发现Unsafe在刻意隐藏,也就前面说的不推荐上传应用使用该类。

并发包内提供了LockSupport封装了Unsafe对象的类,一般我们都用这个封装类。

public class LockSupport {
private LockSupport() {} // Cannot be instantiated.
private static final sun.misc.Unsafe UNSAFE;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> tk = Thread.class;
parkBlockerOffset = UNSAFE.objectFieldOffset
(tk.getDeclaredField("parkBlocker"));
} catch (Exception ex) { throw new Error(ex); }
} private static void setBlocker(Thread t, Object arg) {
// Even though volatile, hotspot doesn't need a write barrier here.
UNSAFE.putObject(t, parkBlockerOffset, arg);
} public static void park() {
UNSAFE.park(false, 0L);
} public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, 0L);
setBlocker(t, null);
} public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}
} public class Thread{
volatile Object parkBlocker;
}
主要包含的点:
1.利用Unsafe直接操作内存来设置blocker
parkBlocker是thread中的volatile类型的变量。UNSAFE.objectFieldOffset可以获得这里是blocker的内存偏移offset,即物理内存位置,和c++就一模一样了。
setBlocker方法是把arg对象设置到Thread的parkBlocker属性上。
parkBlocker是用来表明本线程是在哪个对象上阻塞 2.park有两个方法,带参数的就是指明锁对象,即表明该线程锁在那个对象上。不带参数就不表明了。 3.unpark直接唤醒

java.util.concurrent各组件分析 一 sun.misc.Unsafe的更多相关文章

  1. 原子类java.util.concurrent.atomic.*原理分析

    原子类java.util.concurrent.atomic.*原理分析 在并发编程下,原子操作类的应用可以说是无处不在的.为解决线程安全的读写提供了很大的便利. 原子类保证原子的两个关键的点就是:可 ...

  2. java.util.concurrent包详细分析--转

    原文地址:http://blog.csdn.net/windsunmoon/article/details/36903901 概述 Java.util.concurrent 包含许多线程安全.测试良好 ...

  3. 聊聊高并发(二十五)解析java.util.concurrent各个组件(七) 理解Semaphore

    前几篇分析了一下AQS的原理和实现.这篇拿Semaphore信号量做样例看看AQS实际是怎样使用的. Semaphore表示了一种能够同一时候有多个线程进入临界区的同步器,它维护了一个状态表示可用的票 ...

  4. 聊聊高并发(二十九)解析java.util.concurrent各个组件(十一) 再看看ReentrantReadWriteLock可重入读-写锁

    上一篇聊聊高并发(二十八)解析java.util.concurrent各个组件(十) 理解ReentrantReadWriteLock可重入读-写锁 讲了可重入读写锁的基本情况和基本的方法,显示了怎样 ...

  5. 谈论高并发(二十二)解决java.util.concurrent各种组件(四) 深入了解AQS(二)

    上一页介绍AQS其基本设计思路以及两个内部类Node和ConditionObject实现 聊聊高并发(二十一)解析java.util.concurrent各个组件(三) 深入理解AQS(一) 这篇说一 ...

  6. 聊聊高并发(二十)解析java.util.concurrent各个组件(二) 12个原子变量相关类

    这篇说说java.util.concurrent.atomic包里的类,总共12个.网上有非常多文章解析这几个类.这里挑些重点说说. watermark/2/text/aHR0cDovL2Jsb2cu ...

  7. 谈论高并发(三十)解析java.util.concurrent各种组件(十二) 认识CyclicBarrier栅栏

    这次谈话CyclicBarrier栅栏,如可以从它的名字可以看出,它是可重复使用. 它的功能和CountDownLatch类别似,也让一组线程等待,然后开始往下跑起来.但也有在两者之间有一些差别 1. ...

  8. java对象的内存布局(二):利用sun.misc.Unsafe获取类字段的偏移地址和读取字段的值

    在上一篇文章中.我们列出了计算java对象大小的几个结论以及jol工具的使用,jol工具的源代码有兴趣的能够去看下.如今我们利用JDK中的sun.misc.Unsafe来计算下字段的偏移地址,一则验证 ...

  9. 聊聊高并发(四十)解析java.util.concurrent各个组件(十六) ThreadPoolExecutor源代码分析

    ThreadPoolExecutor是Executor运行框架最重要的一个实现类.提供了线程池管理和任务管理是两个最主要的能力.这篇通过分析ThreadPoolExecutor的源代码来看看怎样设计和 ...

随机推荐

  1. React中useEffect使用

    2019-08-24 07:00:00 文摘资讯 阅读数 1364  收藏 博文的原始地址     之前我们已经掌握了useState的使用,在 class 中,我们通过在构造函数中设置 this.s ...

  2. 层级轮播图(animate)

    层级轮播图(animate) css <style type="text/css"> * { margin: 0; padding: 0; } ul, ol { lis ...

  3. JMS消息传递类型特点介绍

    对于消息的传递有两种类型: 一种是点对点的,即一个生产者和一个消费者一一对应: 另一种是发布/ 订阅模式,即一个生产者产生消息并进行发送后,可以由多个消费者进 行接收. 特点介绍: 点到点模型点对点传 ...

  4. WebSocket数据加密——AES与RSA混合加密

    前言 之前在写“一套简单的web即时通讯”,写到第三版的时候没什么思路,正好微信公众号看到一篇讲API交互加密,于是就自己搞了一套AES与RSA混合加密,无意中产生应用在WebSocket想法,好在思 ...

  5. IDA+Windbg IDA+OD 连动调试插件

    https://github.com/bootleg/ret-sync 使用注意事项:多次测试,最好现在IDA中启动,然后再在OD或WINDBG(.load sync)中启动. 这个工具还是相当给力的 ...

  6. Annotation-specified bean name 'userDaoImpl' for bean class [***] conflicts with existing, non-compatible bean definition of same name and class [***]

    使用Spring开发的时候报错如下: Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionExcept ...

  7. windows server 2008 r2 安装 vs2017 无法进入安装界面问题解决方法

    在 windows server 2008 r2 版本操作系统上安装 vs2017 经常出现下载进度条结束后没有任何反应问题,一般是因为安装程序兼容性造成的,解决方案如下: 将 C:\Program ...

  8. react网页版聊天|仿微信、微博web版|react+pc端仿微信实例

    一.项目介绍 基于react+react-dom+react-router-dom+redux+react-redux+webpack2.0+nodejs等技术混合开发的仿微信web端聊天室react ...

  9. 什么是测试系统工程师(TSE)?

    深圳市共创力研发咨询 杨学明/文 TSE(Test System Engineer)简称测试系统工程师,作为系统工程(SE)团队的一员,很多公司目前还没有这样的角色,导致测试部分往往处理弱势,第一,不 ...

  10. [20190510]rman备份的疑问7.txt

    [20190510]rman备份的疑问7.txt --//上午测试rman备份时备份文件大小回缩的测试.链接:--//http://blog.itpub.net/267265/viewspace-26 ...