首页 > 其他分享 >用Variable Handles来替换Unsafe

用Variable Handles来替换Unsafe

时间:2023-11-07 14:55:06浏览次数:32  
标签:VH Unsafe FIELD Handles memory Variable println VarHandle out

在JDK9中,包含了一个叫Variable Handles的新功能,下面是该功能的描述:

Define a standard means to invoke the equivalents of various java.util.concurrent.atomic and sun.misc.Unsafe operations upon object fields and array elements, a standard set of fence operations for fine-grained control of memory ordering, and a standard reachability-fence operation to ensure that a referenced object remains strongly reachable.

从这段官方描述中我们可以得知,Variable Handles主要是提供java.util.concurrent.atomicsun.misc.Unsafe相似的功能,但会更加安全和易用,并且在并发方面提高了性能。在Java并发包中,由于包中的类大量调用sun.misc.Unsafe提供的功能,官方现在已不推荐再使用sun.misc.Unsafe这个类了,所以看看这个功能十分有必要,例如在AtomicIntegerArray这个类中已经用Variable Handles替换了sun.misc.Unsafe,并且在CAS中也会用到。

说到CAS的应用,我们需要对某一字段进行原子更新,可能会用到以下几种方式:

  1. 使用AtomicInteger类来更新,但会带来额外的内存消耗以及因引用替换带来的新的并发问题;
  2. 使用Atomic*FieldUpdater类来完成字段的原子更新,其是基于反射来实现的,对字段和包装类型有一定的限制,操作开销比较大;
  3. 使用sun.misc.Unsafe提供的JVM内置函数API,这个类提供不安全的操作,损害安全性和移植性,官方不允许开发者使用,以后也会被替代掉。

变量句柄是对变量的类型化引用,它支持在各种访问模式下对变量的读写访问。支持的变量类型包括实例字段、静态字段和数组元素。下面我们来看看它的基础API如何使用。

创建VarHandle需要通过MethodHandles这个类调用其静态方法来实现,根据要访问类的不同类型的成员变量调用不同的静态方法:

  • MethodHandles.lookup 访问类非私有属性
  • MethodHandles.privateLookupIn 访问类的私有属性
  • MethodHandles.arrayElementVarHandle 访问类中的数组

获取到Lookup,然后通过调用findVarHandle方法来获取VarHandle实例,在JDK9中,

  • findVarHandle:用于创建对象中非静态字段的VarHandle。接收参数有三个,第一个为接收者的Class对象,第二个是字段名称,第三个是字段类型。
  • findStaticVarHandle:用于创建对象中静态字段的VarHandle,接收参数与findVarHandle一致。
  • unreflectVarHandle:通过反射字段创建VarHandle。

为了保证效率,VarHandle类的实例通常需要被声明为static final变量(其实就是常量),这样可以在编译期对它进行优化。代码如下:

private static final VarHandle VH_TEST_FIELD_I;
private static final VarHandle VH_TEST_ARRAY;
private static final VarHandle VH_TEST_FIELD_J;

int i = 1;
int[] arr = new int[]{1, 2, 3};
private int j = 2;

static {
    try {
        VH_TEST_FIELD_I = MethodHandles.lookup()
                .in(Test.class)
                .findVarHandle(Test.class, "i", int.class);

        VH_TEST_ARRAY = MethodHandles.arrayElementVarHandle(int[].class);

        VH_TEST_FIELD_J = MethodHandles.privateLookupIn(Test.class, MethodHandles.lookup())
                .findVarHandle(Test.class, "j", int.class);
    } catch (ReflectiveOperationException e) {
        throw new Error(e);
    }
}

获取到了VarHandle实例,接下来可以做些什么呢?VarHandle提供了几种访问模式(access modes):

  1. read access modes, such as reading a variable with volatile memory ordering effects;
  2. write access modes, such as updating a variable with release memory ordering effects;
  3. atomic update access modes, such as a compare-and-set on a variable with volatile memory order effects for both read and writing;
  4. numeric atomic update access modes, such as get-and-add with plain memory order effects for writing and acquire memory order effects for reading.
  5. bitwise atomic update access modes, such as get-and-bitwise-and with release memory order effects for writing and plain memory order effects for reading.

后面三个访问模式被称为 read-modify-write 。从上面5个访问模式来看,主要包括普通变量读写、volatile变量读写和CAS操作。示例代码如下:

public void test() {
    // read
    System.out.println(VH_this_FIELD_I.get(this)); // 1
    System.out.println(VH_this_ARRAY.get(arr, 2)); // 3

    // write
    VH_this_FIELD_I.set(this, 99);
    System.out.println(VH_this_FIELD_I.get(this)); // 99

    VH_this_ARRAY.set(arr, 2, 4);
    System.out.println(VH_this_ARRAY.get(arr, 2)); // 4

    // CAS
    System.out.println(VH_this_FIELD_I.compareAndSet(this, 99, 3)); // true
    System.out.println(VH_this_FIELD_I.get(this)); // 3

    System.out.println(VH_this_ARRAY.compareAndSet(arr, 2, 4, 8)); // true
    System.out.println(VH_this_ARRAY.get(arr, 2)); // 8

    // Numeric Atomic Update
    System.out.println(VH_this_FIELD_I.getAndAdd(this, 6)); // 3
    System.out.println(VH_this_FIELD_I.get(this)); // 9
}

除了上面的五中访问模式外,在JEP 193的描述中,还提供了一组内存屏障(Memory fences)方法,为内存排序提供更细粒度的控制。其中涉及到memory order的概念,与最近的c++ 11内存模型一致,详情请参考其相关概念。

在想要利用CAS去实现我们的逻辑,首先推荐使用VarHandle来实现,它提供了精细粒度的API,更加安全,相信在以后的产品中应用会非常广泛。

参考:


title: 用Variable Handles来替换Unsafe
tags: [VarHandle,java]
author: Mingshan
categories: Java
date: 2018-10-05

标签:VH,Unsafe,FIELD,Handles,memory,Variable,println,VarHandle,out
From: https://www.cnblogs.com/mingshan/p/17793628.html

相关文章

  • Proj. Unknown: Deciding Differential Privacy of Online Algorithms with Multiple
    Paperhttps://arxiv.org/abs/2309.06615Abstract背景:自动机A被称作查分隐私自动机:当对某些D,对任何隐私预算ε>0,该自动机是Dε-differentiallyprivate(ADiPautomatonisaparametricautomatonwhosebehaviordependsontheprivacybudget......
  • OP_REQUIRES failed at save_restore_v2_ops.cc:109 : Permission denied: model/vari
     2021-06-0110:32:15.183997:Wtensorflow/python/util/util.cc:348]Setsarenotcurrentlyconsideredsequences,butthismaychangeinthefuture,soconsideravoidingusing them.2021-06-0110:32:15.639234:Wtensorflow/core/framework/op_kernel.cc:1763]O......
  • Unsafe
     CAS相关publicfinalnativebooleancompareAndSwapObject(Objectvar1,longvar2,Objectvar4,Objectvar5);publicfinalnativebooleancompareAndSwapInt(Objectvar1,longvar2,intvar4,intvar5);publicfinalnativebooleancompareAndSwapLon......
  • 编辑器Scene视图扩展 - Handles.Slider2D
    效果 #ifUNITY_EDITORusingUnityEditor;usingUnityEngine;publicclassTestSceneGUIWindow:EditorWindow{[MenuItem("MyTools/TestSceneGUIWindow")]publicstaticvoidShowWindow(){EditorWindow.GetWindow<TestSceneGU......
  • [901] Reuse variables of CMD batch scripts
    Inabatchfile,youcanreuseavariabletogeneratedifferentfilepathsbyconcatenatingthevariablewithotherstringsorvariables.Here'sanexampleofhowtodothis:@echooffset"base_path=C:\Example"REMGeneratefilepathsus......
  • AtomicInteger源码解读和Unsafe对象
    针对线程安全问题,jdk除提供了加锁的解决方式外还提供了无锁的方式,例如AtomicInteger这个原子整数类,无锁并发的线程安全是通过cas来实现的,这一篇文章就来简单分析下AtomicInteger的源码实现。一、AtomicInteger的简答使用先来看一断非线程安全的代码@Slf4jpublicclassThre......
  • LookHandles.exe软件多开窗口修改标题
    当我们针对某个软件进行多开以后,比如我们多开了电脑版微信。此时,使用UI自动化工具是无法准确确定窗口的,因为窗口的名称和类名都一样我们可以使用LookHandles.exe修改窗口名称修改窗口名称LookHandles.exe使用方法LookHandles.exe点住放大镜,移动到想要修改的窗口上,比如微信窗......
  • LookHandles.exe软件多开窗口修改标题
    当我们针对某个软件进行多开以后,比如我们多开了电脑版微信。此时,使用UI自动化工具是无法准确确定窗口的,因为窗口的名称和类名都一样我们可以使用LookHandles.exe修改窗口名称修改窗口名称LookHandles.exe使用方法LookHandles.exe点住放大镜,移动到想要修改的窗口上,比如微信窗口,然......
  • ‘Proof of the pudding’: Global variables and PAGE_EXECUTE_WRITECOPY
    ‘Proofofthepudding’:GlobalvariablesandPAGE_EXECUTE_WRITECOPYUNCATEGORIZEDPRODUCTIONDEBUGGING, WINDBGLEAVEACOMMENT TodayIwasteachingadebuggingclasstoourcustomers.Asafoundationalelementwenormallyreviewthevirtual-to-phys......
  • @PathVariable注解
    @PathVariable主要作用:映射URL绑定的占位符带占位符的URL是Spring3.0新增的功能,URL中的{xxx}占位符可以通过@PathVariable(“xxx”)绑定到操作方法的入参中。例如:@RequestMapping("/user/{id}")publicStringtestPathVariable(@PathVariable("id")Stringid){System.o......