Java 并发随身记(一)之 Unsafe类
最近在看Java并发相关的内容,需要自己整理整理,不然就生疏了。工作2年多,工作时一般注都是框架、消息这些内容,对基础内容比较忽视。闲话不说,既然是并发内容,首先先复习一下Unsafe的内容吧。
Unsafe 类提供了硬件级别的原子操作,它提供非常有趣的一些内容。首先我们看下Unsafe文件。并对其一些内容进行分析,然后给出具体的用法。网上找了一个部分的源代码,看了一下。基本已经达到我们分享的要求。
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sun.misc; import dalvik.system.VMStack; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; /**
* The package name notwithstanding, this class is the quasi-standard
* way for Java code to gain access to and use functionality which,
* when unsupervised, would allow one to break the pointer/type safety
* of Java.
* <p>
* 该包名不具有代表性.可以通过该类来获取和访问数据,但是容易破坏Java指针和类型的安全性。
*/
public final class Unsafe {
/**
* Traditional dalvik name.
* 内部维护一个静态的 Unsafe 实例
*/
private static final Unsafe THE_ONE = new Unsafe();
/**
* Traditional RI name.
*/
private static final Unsafe theUnsafe = THE_ONE; /**
* This class is only privately instantiable.
* <p>
* 说明该类不能被new 出来
*/
private Unsafe() {
} /**
* Gets the unique instance of this class. This is only allowed in
* very limited situations.
* <p>
* 静态方法,通过getUnsafe方法获取一个Unsafe 实例
*/
public static Unsafe getUnsafe() {
/*
* Only code on the bootclasspath is allowed to get at the
* Unsafe instance.
*
* 只有在 bootclasspath下的Java类才能获取得到该实例,否则抛异常。
*/
ClassLoader calling = VMStack.getCallingClassLoader();
if ((calling != null) && (calling != Unsafe.class.getClassLoader())) {
throw new SecurityException("Unsafe access denied");
}
return THE_ONE;
} /**
* Gets the raw byte offset from the start of an object's memory to
* the memory used to store the indicated instance field.
* <p>
* 获取从对象内存开头到用于存储指示实例字段的内存的原始字节偏移量。也就是
* 获取某对象内的变量的相对地址偏移量
*
* @param field non-null; the field in question, which must be an
* instance field
* @return the offset to the field
*/
public long objectFieldOffset(Field field) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalArgumentException(
"valid for instance fields only");
}
return objectFieldOffset0(field);
} /**
* Helper for {@link #objectFieldOffset}, which does all the work,
* assuming the parameter is deemed valid.
* <p>
* 本地方法,获取对象属性的偏移量
*
* @param field non-null; the instance field
* @return the offset to the field
*/
private static native long objectFieldOffset0(Field field); /**
* Gets the offset from the start of an array object's memory to
* the memory used to store its initial (zeroeth) element.
* <p>
* 获取数组对象的起始位置
*
* @param clazz non-null; class in question; must be an array class
* @return the offset to the initial element
*/
public int arrayBaseOffset(Class clazz) {
if (!clazz.isArray()) {
throw new IllegalArgumentException(
"valid for array classes only");
}
return arrayBaseOffset0(clazz);
} /**
* Helper for {@link #arrayBaseOffset}, which does all the work,
* assuming the parameter is deemed valid.
*
* @return the offset to the field
*/
private static native int arrayBaseOffset0(Class clazz); /**
* Gets the size of each element of the given array class.
* <p>
* 获取给定数组类的每个元素的大小
*
* @param clazz non-null; class in question; must be an array class
* @return > 0; the size of each element of the array
*/
public int arrayIndexScale(Class clazz) {
if (!clazz.isArray()) {
throw new IllegalArgumentException(
"valid for array classes only");
}
return arrayIndexScale0(clazz);
} /**
* Helper for {@link #arrayIndexScale}, which does all the work,
* assuming the parameter is deemed valid.
*
* @return the offset to the field
*/
private static native int arrayIndexScale0(Class clazz); /**
* Performs a compare-and-set operation on an <code>int</code>
* field within the given object.
* <p>
* 比较置换操作(CAS)for int
*
* @param obj non-null; object containing the field
* @param offset offset to the field within <code>obj</code>
* @param expectedValue expected value of the field
* @param newValue new value to store in the field if the contents are
* as expected
* @return <code>true</code> if the new value was in fact stored, and
* <code>false</code> if not
*/
public native boolean compareAndSwapInt(Object obj, long offset,
int expectedValue, int newValue); /**
* Performs a compare-and-set operation on a <code>long</code>
* field within the given object.
* <p>
* 比较置换操作(CAS)for long
*
* @param obj non-null; object containing the field
* @param offset offset to the field within <code>obj</code>
* @param expectedValue expected value of the field
* @param newValue new value to store in the field if the contents are
* as expected
* @return <code>true</code> if the new value was in fact stored, and
* <code>false</code> if not
*/
public native boolean compareAndSwapLong(Object obj, long offset,
long expectedValue, long newValue); /**
* Performs a compare-and-set operation on an <code>Object</code>
* field (that is, a reference field) within the given object.
* <p>
* 比较置换操作(CAS) for object
*
* @param obj non-null; object containing the field
* @param offset offset to the field within <code>obj</code>
* @param expectedValue expected value of the field
* @param newValue new value to store in the field if the contents are
* as expected
* @return <code>true</code> if the new value was in fact stored, and
* <code>false</code> if not
*/
public native boolean compareAndSwapObject(Object obj, long offset,
Object expectedValue, Object newValue); /**
* Gets an <code>int</code> field from the given object,
* using <code>volatile</code> semantics.
* 获取 对象 obj 偏移量offset 的值 (int)
*
* @param obj non-null; object containing the field
* @param offset offset to the field within <code>obj</code>
* @return the retrieved value
*/
public native int getIntVolatile(Object obj, long offset); /**
* Stores an <code>int</code> field into the given object,
* using <code>volatile</code> semantics.
* <p>
* 把值newValue 放到对象obj 偏移量为offset 上 (int)
*
* @param obj non-null; object containing the field
* @param offset offset to the field within <code>obj</code>
* @param newValue the value to store
*/
public native void putIntVolatile(Object obj, long offset, int newValue); /**
* Gets a <code>long</code> field from the given object,
* using <code>volatile</code> semantics.
* <p>
* 获取 对象 obj 偏移量offset 的值 (long)
*
* @param obj non-null; object containing the field
* @param offset offset to the field within <code>obj</code>
* @return the retrieved value
*/
public native long getLongVolatile(Object obj, long offset); /**
* Stores a <code>long</code> field into the given object,
* using <code>volatile</code> semantics.
* <p>
* 把值newValue 放到对象obj 偏移量为offset 上 (long)
*
* @param obj non-null; object containing the field
* @param offset offset to the field within <code>obj</code>
* @param newValue the value to store
*/
public native void putLongVolatile(Object obj, long offset, long newValue); /**
* Gets an <code>Object</code> field from the given object,
* using <code>volatile</code> semantics.
* 获取 对象 obj 偏移量offset 的值 (object)
*
* @param obj non-null; object containing the field
* @param offset offset to the field within <code>obj</code>
* @return the retrieved value
*/
public native Object getObjectVolatile(Object obj, long offset); /**
* Stores an <code>Object</code> field into the given object,
* using <code>volatile</code> semantics.
* <p>
* 把值newValue 放到对象obj 偏移量为offset 上 (object)
*
* @param obj non-null; object containing the field
* @param offset offset to the field within <code>obj</code>
* @param newValue the value to store
*/
public native void putObjectVolatile(Object obj, long offset,
Object newValue); /**
* Gets an <code>int</code> field from the given object.
*
* @param obj non-null; object containing the field
* @param offset offset to the field within <code>obj</code>
* @return the retrieved value
*/
public native int getInt(Object obj, long offset); /**
* Stores an <code>int</code> field into the given object.
*
* @param obj non-null; object containing the field
* @param offset offset to the field within <code>obj</code>
* @param newValue the value to store
*/
public native void putInt(Object obj, long offset, int newValue); /**
* Lazy set an int field.
*/
public native void putOrderedInt(Object obj, long offset, int newValue); /**
* Gets a <code>long</code> field from the given object.
*
* @param obj non-null; object containing the field
* @param offset offset to the field within <code>obj</code>
* @return the retrieved value
*/
public native long getLong(Object obj, long offset); /**
* Stores a <code>long</code> field into the given object.
*
* @param obj non-null; object containing the field
* @param offset offset to the field within <code>obj</code>
* @param newValue the value to store
*/
public native void putLong(Object obj, long offset, long newValue); /**
* Lazy set a long field.
*/
public native void putOrderedLong(Object obj, long offset, long newValue); /**
* Gets an <code>Object</code> field from the given object.
*
* @param obj non-null; object containing the field
* @param offset offset to the field within <code>obj</code>
* @return the retrieved value
*/
public native Object getObject(Object obj, long offset); /**
* Stores an <code>Object</code> field into the given object.
*
* @param obj non-null; object containing the field
* @param offset offset to the field within <code>obj</code>
* @param newValue the value to store
*/
public native void putObject(Object obj, long offset, Object newValue); /**
* Lazy set an object field.
*/
public native void putOrderedObject(Object obj, long offset,
Object newValue); /**
* Parks the calling thread for the specified amount of time,
* unless the "permit" for the thread is already available (due to
* a previous call to {@link #unpark}. This method may also return
* spuriously (that is, without the thread being told to unpark
* and without the indicated amount of time elapsing).
* <p>
* <p>See {@link java.util.concurrent.locks.LockSupport} for more
* in-depth information of the behavior of this method.</p>
* <p>
* 除非当前线程已经可用(比如调用unpark),否则挂起当前线程time 时间,
*
* @param absolute whether the given time value is absolute
* milliseconds-since-the-epoch (<code>true</code>) or relative
* nanoseconds-from-now (<code>false</code>)
* @param time the (absolute millis or relative nanos) time value
*/
public void park(boolean absolute, long time) {
if (absolute) {
Thread.currentThread().parkUntil(time);
} else {
Thread.currentThread().parkFor(time);
}
} /**
* Unparks the given object, which must be a {@link Thread}.
* <p>
* 恢复指定线程
* <p>
* <p>See {@link java.util.concurrent.locks.LockSupport} for more
* in-depth information of the behavior of this method.</p>
*
* @param obj non-null; the object to unpark
*/
public void unpark(Object obj) {
if (obj instanceof Thread) {
((Thread) obj).unpark();
} else {
throw new IllegalArgumentException("valid for Threads only");
}
} /**
* Allocates an instance of the given class without running the constructor.
* <p>
* 不通过构造器,分配一个类的实例
* The class' <clinit> will be run, if necessary.
*/
public native Object allocateInstance(Class<?> c);
}
从上面的注释,大概可以看出Unsafe都干了什么事情,其实它干的事情就如C语言操作数据地址。接下来我们需要如何使用提供的Api.
首先,我们无法通过Unsafe.getUnsafe()方法来创建一个Unsafe实例,因为他需要时bootclasspath下的类才能使用它,所以我们需要通过反射的方法得到这个类的对象。代码如下:
public static Unsafe getUnsafe() {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
return unsafe;
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
这样我们就得到了这个Unsafe对象,接下来我们来看下如何以上的方法。下面的栗子看起来比较鸡肋,但是它可以帮助我们如何使用以上的api.主要是向类型为User的对象不通过get,set方法来获取,设置值。而是通过Unsafe类。
工具类(GASUtils)
package com.qee.unsafe;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class GASUtils {
private static final Unsafe UNSAFE = getUnsafe();
private static Unsafe getUnsafe() {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
return unsafe;
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
/**
* 获取一个对象属性值(该属性是int 类型)
*
* @param object
* @param paramName
* @return
*/
public static Integer getInt(Object object, String paramName) {
try {
long offset = UNSAFE.objectFieldOffset(object.getClass().getDeclaredField(paramName));
return UNSAFE.getIntVolatile(object, offset);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return null;
}
/**
* 设置一个对象属性值(该属性是int 类型)
*
* @param object
* @param paramName
* @param value
*/
public static void setInt(Object object, String paramName, int value) {
try {
long offset = UNSAFE.objectFieldOffset(object.getClass().getDeclaredField(paramName));
UNSAFE.putIntVolatile(object, offset, value);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
/**
* 获取一个对象属性值(该属性是Object 类型)
*
* @param object
* @param paramName
* @return
*/
public static Object getObject(Object object, String paramName) {
try {
long offset = UNSAFE.objectFieldOffset(object.getClass().getDeclaredField(paramName));
return UNSAFE.getObjectVolatile(object, offset);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return null;
}
/**
* 设置一个对象属性值(该属性是Object 类型)
*
* @param object
* @param paramName
* @param value
*/
public static void setObject(Object object, String paramName, Object value) {
try {
long offset = UNSAFE.objectFieldOffset(object.getClass().getDeclaredField(paramName));
UNSAFE.putObjectVolatile(object, offset, value);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
/**
* cas 比较设置,返回对象里面的值(Int)
*
* @param object
* @param paramName
* @param expectValue
* @param updateValue
* @return
*/
public static int compareAndSetInt(Object object, String paramName, int expectValue, int updateValue) {
try {
long offset = UNSAFE.objectFieldOffset(object.getClass().getDeclaredField(paramName));
boolean b = UNSAFE.compareAndSwapInt(object, offset, expectValue, updateValue);
if (b) {
return updateValue;
}
return UNSAFE.getIntVolatile(object, offset);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return getInt(object, paramName);
}
}
测试对象(User)
package com.qee.unsafe;
import java.io.Serializable;
public class User implements Serializable {
private String name;
private int age;
private boolean sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
}
Main类:
package com.qee.unsafe;
public class UnsafeTest {
public static void main(String[] args) throws NoSuchFieldException {
User user = new User();
GASUtils.setInt(user, "age", 10);
System.out.println("GASUtils.getInt :" + GASUtils.getInt(user, "age"));
System.out.println("user.getAge(): " + user.getAge());
GASUtils.setObject(user, "name", "candy");
System.out.println("GASUtils.getObject :" + GASUtils.getObject(user, "name"));
System.out.println("user.getName(): " + user.getName());
int age1 = GASUtils.compareAndSetInt(user, "age", 11, 11);
int age2 = GASUtils.compareAndSetInt(user, "age", 10, 11);
System.out.println("age1: " + age1);
System.out.println("age2: " + age2);
}
}
结果:

Java 并发随身记(一)之 Unsafe类的更多相关文章
- [转]JAVA并发编程学习笔记之Unsafe类
1.通过Unsafe类可以分配内存,可以释放内存:类中提供的3个本地方法allocateMemory.reallocateMemory.freeMemory分别用于分配内存,扩充内存和释放内存,与C语 ...
- 并发编程之sun.misc.Unsafe类
1.Unsafe知识点整理 2.代码: package com.javabasic.unsafe; import java.lang.reflect.Field; import sun.misc.Un ...
- java并发编程基础——线程相关的类
线程相关类 java还为线程安全提供了一些工具类. 一.ThreadLocal类(Thread Local Variable) ThreadLocal类,是线程局部变量的意思.功用非常简单,就是为每一 ...
- Java并发编程:Future接口、FutureTask类
在前面的文章中我们讲述了创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口. 这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果. 如果需要获取执行结果,就 ...
- Java并发编程(三)Thread类的使用
一.线程的状态 线程从创建到最终的消亡,要经历若干个状态.一般来说,线程包括以下这几个状态:创建(new).就绪(runnable).运行(running).阻塞(blocked).time wait ...
- Java并发基础10:原子性操作类的使用
在 java5 以后,我们接触到了线程原子性操作,也就是在修改时我们只需要保证它的那个瞬间是安全的即可,经过相应的包装后可以再处理对象的并发修改,本文总结一下Atomic系列的类的使用方法,其中包含: ...
- Java Unsafe类
参考了这篇文章:http://blog.csdn.net/aesop_wubo/article/details/7537278 <JAVA并发编程学习笔记之Unsafe类> Unsafe开 ...
- Java并发编程:浅析几种线程安全模型 [转]
多线程编程一直是老生常谈的问题,在Java中,随着JDK的逐渐发展,JDK提供给我们的并发模型也越来越多,本文摘取三例使用不同原理的模型,分析其大致原理.目录如下: 1.COW之CopyOnWrite ...
- Java并发--Java中的CAS操作和实现原理
版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/CringKong/article/deta ...
随机推荐
- 阿里云服务器 centos 7 安装postgresql 11
Postgresql简介 官方网站:https://www.postgresql.org/ 简介参考zhihu文章 https://www.zhihu.com/question/20010554 关于 ...
- java 修改字体大小
在Windows->Preferences->General->Appearance->Colors and Fonts->Java->Java Editor Te ...
- Codeforces 509E Pretty Song (思维)
E. Pretty Song time limit per test:1 seco ...
- [Math Review] Linear Algebra for Singular Value Decomposition (SVD)
Matrix and Determinant Let C be an M × N matrix with real-valued entries, i.e. C={cij}mxn Determinan ...
- 【IDEA】(3)---非常实用提高开发效率和水平的插件
IDEA(3)-Mac中IDEA插件 IDEA提供了许多很实用的插件,能够大大提高开发效率和开发水平,这里列举几个很实用的插件. 说明:这边的IDEA是MAC系统. 一.插件管理界面简介 1.界面位置 ...
- BZOJ——3412: [Usaco2009 Dec]Music Notes乐谱
http://www.lydsy.com/JudgeOnline/problem.php?id=3412 Time Limit: 3 Sec Memory Limit: 128 MBSubmit: ...
- 2016集训测试赛(二十四)Problem C: 棋盘控制
Solution 场上的想法(显然是错的)是这样的: 我们假设棋子是一个一个地放置的, 考虑在放置棋子的过程中可能出现哪些状态. 我们令有序整数对\((i, j)\)表示总共控制了\(i\)行\(j\ ...
- Flutter开发记录part1
(1)AppBar:automaticallyImplyLeading//是否带返回leading箭头 (2)非route路由页面跳转 :Navigator.of(context).push(Mate ...
- (转)ubuntu/var/log/下各个日志文件
本文简单介绍ubuntu/var/log/下各个日志文件,方便出现错误的时候查询相应的log /var/log/alternatives.log-更新替代信息都记录在这个文件中 /var/log/ ...
- GDI+重绘笔记
有的控件不能重载 OnPaint,设置 ControlStyles.UserPaint = true即可 //如果为 true,控件将自行绘制,而不是通过操作系统来绘制. //如果为 false,将不 ...