目录
VarHandle
一、主程序
二、属性类
三、对属性进行加法操作
四、对属性进行减法操作
五、执行结果
Java9的新特性,它允许获得一个类型参考,以在不同的模式中访问一个变量(实例字段、静态字段或数组元素)。
在Java9之前,只能获得原子性变量的行为,现在,可以使用变量句柄来获得相同的功能而不用任何同步机制。(即,你可以操作普通变量时,使其原子性的变化。)
程序分別对Account的2个属性进行了10000次的加法和减法。线程安全的操作结果一定为0.非安全的操作可能不为零。
package xyz.jangle.thread.test.n7_XI.varhandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
/**
* 7.11、变量句柄 VarHandle 程序分別对Account的2个属性进行了10000次的加法和减法。
* 线程安全的操作结果一定为0.非安全的操作可能不为零。
*
* @author jangle
* @email [email protected]
* @time 2020年9月19日 下午5:59:42
*
*/
public class M {
public static void main(String[] args) {
Account account = new Account();
var inc = new Thread(new Incrementer(account));
var dec = new Thread(new Decrementer(account));
inc.start();
dec.start();
try {
inc.join();
dec.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("安全的属性操作:" + account.amount);
System.out.println("非安全的属性操作:" + account.unsafeAmount);
try {
VarHandle handle = MethodHandles.lookup().in(Account.class).findVarHandle(Account.class, "amount",
double.class);
// 读取变量,如同该值声明了volatile
var amount = handle.getVolatile(account);
// 读取变量,如同该值未声明volatile
var amount2 = handle.get(account);
// 读取变量,保证指令优化之前,后续的修改或访问该变量的指令不会被重排序
var amount3 = handle.getAcquire(account);
// 读取变量,保证当前线程中的指令不会重排序,但不保证其他线程。
var amount4 = handle.getOpaque(account);
System.out.println(amount + "," + amount2 + "," + amount3 + "," + amount4);
VarHandle handle2 = MethodHandles.lookup().in(Account.class).findVarHandle(Account.class, "unsafeAmount",
double.class);
var unsafeAmount = handle2.get(account);
System.out.println(unsafeAmount);
// 设置变量,如同该值未声明volatile
handle2.set(account,999);
System.out.println(handle2.get(account));
// 设置变量,如同该值声明了volatile
handle2.setVolatile(account,777);
System.out.println(handle2.getVolatile(account));
// 设置变量,保证指令优化之前,后续的修改或访问该变量的指令不会被重排序
handle2.setRelease(account,666);
System.out.println(handle2.getAcquire(account));
// 设置变量,保证当前线程中的指令不会重排序,但不保证其他线程。
handle2.setOpaque(account,555);
System.out.println(handle2.getOpaque(account));
// handle2.weakCompareAndSet(account,555.0,333);
// handle2.compareAndSet(account,555.0,333);
// System.out.println(handle2.get(account));
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
package xyz.jangle.thread.test.n7_XI.varhandle;
/**
* 属性类
* @author jangle
* @email [email protected]
* @time 2020年9月19日 下午6:03:08
*
*/
public class Account {
public double amount;
public double unsafeAmount;
public Account() {
super();
this.amount = 0;
this.unsafeAmount = 0;
}
}
package xyz.jangle.thread.test.n7_XI.varhandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
/**
* 对变量进行加法操作
*
* @author jangle
* @email [email protected]
* @time 2020年9月19日 下午6:09:33
*
*/
public class Incrementer implements Runnable {
private Account account;
public Incrementer(Account account) {
super();
this.account = account;
}
@Override
public void run() {
VarHandle handler;
try {
for (int i = 0; i < 10000; i++) {
handler = MethodHandles.lookup().in(Account.class).findVarHandle(Account.class, "amount", double.class);
handler.getAndAdd(account, 100);
account.unsafeAmount += 100;
}
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
package xyz.jangle.thread.test.n7_XI.varhandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
/**
* 对变量进行减法操作
*
* @author jangle
* @email [email protected]
* @time 2020年9月19日 下午6:04:30
*
*/
public class Decrementer implements Runnable {
private Account account;
public Decrementer(Account account) {
super();
this.account = account;
}
@Override
public void run() {
VarHandle handler;
try {
handler = MethodHandles.lookup().in(Account.class).findVarHandle(Account.class, "amount", double.class);
for (int i = 0; i < 10000; i++) {
handler.getAndAdd(account, -100);
account.unsafeAmount -= 100;
}
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
安全的属性操作:0.0
非安全的属性操作:-200.0
0.0,0.0,0.0,0.0
-200.0
999.0
777.0
666.0
555.0