【实战Java高并发程序设计 1】Java中的指针:Unsafe类

是《实战Java高并发程序设计》第4章的几点。

如果你对技术有着不折不挠的追求,应该还会特别在意incrementAndGet() 方法中compareAndSet()的实现。现在,就让我们更进一步看一下它把!

public final boolean compareAndSet(int expect, int update){
    returnunsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

在这里,我们看到一个特殊的变量unsafe。它是sun.misc.Unsafe类型。从名字看,这个类应该是封装了一些不安全的操作。那什么操作是不安全的呢?学习过C或者C++的话,大家应该知道,指针是不安全的。这也是在Java中把指针去除的重要原因。如果指针指错了位置,或者计算指针偏移量时出错,结果可能是灾难性的,你很有可能会覆盖别人的内存,导致系统奔溃。

而这里的Unsafe就是封装了一些类似指针的操作。compareAndSwapInt()方法是一个navtive方法。它的几个参数含义如下:

public final native boolean compareAndSwapInt(Object o,long offset,int expected,int x);

第一个参数o为给定的对象,offset为对象内的偏移量(其实就是一个字段到对象头部的偏移量,通过这个偏移量可以快速定位字段),expected表示期望值,x表示要设置的值。如果指定的字段的值等于expected,那么就会把它设置为x。

不难看出,compareAndSwapInt()方法的内部,必然是使用CAS原子指令来完成的。此外,Unsafe类还提供了一些方法,主要有以下几个(以Int操作为例,其他数据类型是类似的):

//获得给定对象偏移量上的int值
public native int getInt(Object o, long offset);
//设置给定对象偏移量上的int值
public native void putInt(Object o, long offset, int x);
//获得字段在对象中的偏移量
public native long objectFieldOffset(Field f);
//设置给定对象的int值,使用volatile语义
public native void putIntVolatile(Object o, long offset,int x);
//获得给定对象对象的int值,使用volatile语义
public native int    getIntVolatile(Object o, long offset);
//和putIntVolatile()一样,但是它要求被操作字段就是volatile类型的
public native void putOrderedInt(Object o, long offset, intx);

如果大家还记得“3.3.4 深度剖析ConcurrentLinkedQueue”一节中的描述的ConcurrentLinkedQueue实现,应该对ConcurrentLinkedQueue中的Node还有些印象。Node一些CAS操作也都是使用Unsafe类来实现的。大家可以回顾一下,以加深对Unsafe类的印象。

这里就可以看到,虽然Java抛弃了指针。但是在关键时刻,类似指针的技术还是必不可少的。这里底层的Unsafe实现就是最好的例子。但是很不幸,JDK的开发人员并不希望大家使用这个类。获得Unsafe实例的方法是调动其工厂方法getUnsafe()。但是,它的实现却是这样:

public static Unsafe getUnsafe() {
    Class cc =Reflection.getCallerClass();
    if(cc.getClassLoader() != null)
        throw newSecurityException("Unsafe");
    return theUnsafe;
}

注意加粗部分的代码,它会检查调用getUnsafe()函数的类,如果这个类的ClassLoader不为null,就直接抛出异常,拒绝工作。因此,这也使得我们自己的应用程序无法直接使用Unsafe类。它是一个JDK内部使用的专属类。

注意:根据Java 类加载器的工作原理,应用程序的类由AppLoader加载。而系统核心类,如rt.jar中的类由Bootstrap类加载器加载。Bootstrap加载器没有Java对象的对象,因此试图获得这个类加载器会返回null。所以,当一个类的类加载器为null时,说明它是由Bootstrap加载的,而这个类也极有可能是rt.jar中的类。

这本书:

时间: 2024-10-09 06:01:45

【实战Java高并发程序设计 1】Java中的指针:Unsafe类的相关文章

【实战Java高并发程序设计 3】带有时间戳的对象引用:AtomicStampedReference

[实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference AtomicReference无法解决上述问题的根本是因为对象在修改过程中,丢失了状态信息.对象值本身与状态被画上了等号.因此,我们只要能够记录对象在修改过程中的状态值,就可以很好的解决对象被反复修改导致线程无法正确判断对象状态的问题. AtomicStampedReference正是这么做的.它内部不仅维护了对象值,还维护了一个时间戳(我这里把它

【实战Java高并发程序设计 5】让普通变量也享受原子操作

[实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象引用:AtomicStampedReference [实战Java高并发程序设计 4]数组也能无锁:AtomicIntegerArray 有时候,由于初期考虑不周,或者后期的需求变化,一些普通变量可能也会有线程安全的需求.如果改动不大,我们可以简单地修改程序中每一个使用或者读取这个变量的地方.但显然

【实战Java高并发程序设计 7】让线程之间互相帮助--SynchronousQueue的实现

[实战Java高并发程序设计 1]Java中的指针:Unsafe类 [实战Java高并发程序设计 2]无锁的对象引用:AtomicReference [实战Java高并发程序设计 3]带有时间戳的对象引用:AtomicStampedReference [实战Java高并发程序设计 4]数组也能无锁:AtomicIntegerArray [实战Java高并发程序设计 5]让普通变量也享受原子操作 [实战Java高并发程序设计6]挑战无锁算法:无锁的Vector实现 在对线程池的介绍中,提到了一个非

我的《实战java高并发程序设计》纸质书上市了

在过去单核CPU时代,单任务在一个时间点只能执行单一程序,随着多核CPU的发展,并行程序开发就显得尤为重要. <实战Java高并发程序设计>主要介绍基于Java的并行程序设计基础.思路.方法和实战.首先,立足于并发程序基础,详细介绍Java中进行并行程序设计的基本方法.第二,进一步详细介绍JDK中对并行程序的强大支持,帮助读者快速.稳健地进行并行程序开发.第三,详细讨论有关"锁"的优化和提高并行程序性能级别的方法和思路.第四,介绍并行的基本设计模式及Java8对并行程序的支

【实战Java高并发程序设计 4】数组也能无锁:AtomicIntegerArray

除了提供基本数据类型外,JDK还为我们准备了数组等复合结构.当前可用的原子数组有:AtomicIntegerArray.AtomicLongArray和AtomicReferenceArray,分别表示整数数组.long型数组和普通的对象数组. 这里以AtomicIntegerArray为例,展示原子数组的使用方式. AtomicIntegerArray本质上是对int[]类型的封装.使用Unsafe类通过CAS的方式控制int[]在多线程下的安全性.它提供了以下几个核心API: //获得数组第

Java高并发程序设计(十)--无锁

锁是一种悲观策略,总是觉得会出问题,所以小心翼翼地操作. 无锁是一种乐观策略,总是假设不会出现问题,如果出现问题,那就重新操作.无锁一般使用CAS作为策略. 比较交换CAS: CAS算法包括三个参数:需要更新的变量,预期值,更新值.只有当需要更新的值等于预期值时,说明其他线程没有对它进行操作,使需要更新值等于更新值. 在java.util.concurrent.atomic中,实现了很多无锁的类型: 用AtomicInteger写个小例子: public class demo implement

一图搞定【实战Java高并发程序设计】

来了解下java并发的技术点吧.

实战java高并发程序设计 1

重要概念 同步(synchronous)和异步(asynchronous) 同步等待方法返回 异步瞬间返回,继续下一次调用 并发(Concurrency)和并行(Parallelism) 并发与并行外界表现一致 单核心cpu无法并行,但可以处理并行事务 临界区 公共资源或者共享数据 多线程访问时,可能造成临界区数据破坏 阻塞(Blocking)和非阻塞(Non-Blocking) 非阻塞允许多个线程同时进入临界区 死锁(Deadlock).饥饿(Starvation)和活锁(Livelock)

JAVA高并发程序设计学习-JDK并发包:同步控制一

JDK内部提供了大量的API和框架,这里主要介绍三部分 多线程同步控制方法 线程池,提高线程调度的性能 JDK的并发容器 重入锁:java.util.concurrent.locks.ReenterLock 在代码中,类ReenterLock实现了Runnable,其中有static的变量i,在run()方法中会对i进行自增操作. 自增操作的步骤为:get-set,先获取值再增加值. 如果在这里不进行控制的话,会导致get的值不是最新set的值. 因此,在自增的时候使用锁进行控制,保证get-s