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. Python连载6-time包函数简介

    一.接连载5中time模块 1.函数:altzone (1)含义:获取当前时间与UTC时间相差的秒数,再有夏令时的情况下. (2)格式:time.altzone 2.函数:daylight (1)含义 ...

  2. 【JS】JS实现Html转义和反转义(html编码和解码)的方法总结

    1.JS实现html转义和反转义主要有两种方式: 1).利用用浏览器内部转换器实现html转义: 2).用正则表达式实现html转义: 2.封装的JS工具类: var HtmlUtil = { /*1 ...

  3. Python 相对路径和绝对路径--python实战(九)

    一 背景信息 最近在运行python程序的过程中,无意遇到了这个一个问题,在同事那边一直执行ok的程序,到我这里怎么都有个错误,当初报的错误是这样的: FileNotFoundError: [Errn ...

  4. centos6和centos7的防火墙基本命令

    一.centos6: 1.firewall的基本启动/停止/重启命令 $查看防火墙状态: service iptables status (/etc/init.d/iptables status) $ ...

  5. PHP面试题大全(值得收藏)

    PHP进阶.面试:文档.视频资源点击免费获取 一 .PHP基础部分 1.PHP语言的一大优势是跨平台,什么是跨平台? PHP的运行环境最优搭配为Apache+MySQL+PHP,此运行环境可以在不同操 ...

  6. CSS-页面超出手机屏幕

    手机页面左滑,页面超出手机屏幕. 解决方法: html,body{ overflow-x: hidden; } 从而解决问题,锁住横向滑动的屏幕.

  7. RPA中房产证的 OCR 识别

    客户需求,识别一些证件内容,包括身份证.户口本.营业执照.银行卡以及房产证,前四个比较容易实现,不管是艺赛旗的 RPA 还是百度的 OCR 都有接口,直接调用即可,但是都没有房产证的 OCR 识别,只 ...

  8. 用友的SPS定义

    基于标准产品的支持服务(Standard Product Support,SPS).主要包括:更新升级(软件补丁更新与产品升级).问题解决(产品问题在线或热线解析).知识转移(用友到客户的知识传递). ...

  9. windows下dubbo-admin2.6.x之后版本的安装

    安装zookeeper(单机) 下载bin.tar.gz的版本,解压 conf下的zoo_sample.cfg改zoo.cfg zoo.cfg里添加配置 dataDir=G:/zookeeper-/d ...

  10. 被 GANs 虐千百遍后,我总结出来的 10 条训练经验

    一年前,我决定开始探索生成式对抗网络(GANs).自从我对深度学习产生兴趣以来,我就一直对它们很着迷,主要是因为深度学习能做到很多不可置信的事情.当我想到人工智能的时候,GAN是我脑海中最先出现的一个 ...