热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:Atomic&Unsafe

本文由编程笔记#小编为大家整理,主要介绍了Atomic&Unsafe相关的知识,希望对你有一定的参考价值。1、AutomicJava中
本文由编程笔记#小编为大家整理,主要介绍了Atomic & Unsafe相关的知识,希望对你有一定的参考价值。

1、Automic
  Java中 Atomic 是指一个操作是不可中断的。即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。 所谓原子类说简单点就是具有原子/原子操作特征的类。Java从JDK1.5开始提供了java.util.concurrent.atomic包,方便程序员在多线程环境下,无锁的进行原子操作。

  在java中可以通过锁和循环CAS的方式来实现原子操作。

JVM中的CAS操作正是利用了上文中提到的处理器提供的CMPXCHG指令实现的。自旋CAS实现的基本思路就是循环进行CAS操作直到成功为止,具体的类可以参见juc下的atomic包内的原子类。

  在Atomic包里一共有12个类,四种原子更新方式,分别是原子更新基本类型,原子更新数组,原子更新引用和原子更新字段。Atomic包里的类基本都是使用Unsafe实现的包装类。


1.2、 原子类分类

  基本类型

    使用原子的方式更新基本类型



  • AtomicInteger:整形原子类

  • AtomicLong:长整型原子类

  • AtomicBoolean:布尔型原子类



  数组类型

    使用原子的方式更新数组里的某个元素



  • AtomicIntegerArray:整形数组原子类

  • AtomicLongArray:长整形数组原子类

  • AtomicReferenceArray:引用类型数组原子类



  引用类型



  • AtomicReference:引用类型原子类


 



  • AtomicStampedReference:原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于解决原子的更新数据和数据的版本号,可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题


 

 



  • AtomicMarkableReference :原子更新带有标记位的引用类型


 

  对象的属性修改类型

 



  • AtomicIntegerFieldUpdater:原子更新整形字段的更新器


 

 



  • AtomicLongFieldUpdater:原子更新长整形字段的更新器


 



  • AtomicReferenceFieldUpdater 




1.3 Atomic 的使用

 以 AtomicInteger 为例:

(1)AtomicInteger 的常用方法:

 

public final int get() //获取当前的值
public final int getAndSet(int newValue)//获取当前的值,并设置新的值
public final int getAndIncrement()//获取当前的值,并自增
public final int getAndDecrement() //获取当前的值,并自减
public final int getAndAdd(int delta) //获取当前的值,并加上预期的值
boolean compareAndSet(int expect, int update) //如果输入的数值等于预期值,则以原子方式将该值设置为输入值(update)
public final void lazySet(int newValue)//最终设置为newValue,使用 lazySet 设置之后可能导致其他线程在之后的一小段时间内还是可以读到旧的值。

 

  

 

(2)AtomicInteger 的实现原理

 

//setup to use Unsafe.compareAndSwapInt for updates(更新操作时提供“比较并替换”的作用)
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static
{
try
{
valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
}
catch (Exception ex)
{
throw new Error(ex);
}
}
private volatile int value;

 

  AtomicInteger 类主要利用 CAS (compare and swap) + volatile 和 native 方法来保证原子操作,从而避免 synchronized的高开销,执行效率大为提升。CAS的原理是拿期望的值和原本的一个值作比较,如果相同则更新成新的值。UnSafe 类的 objectFieldOffset()方法是一个本地方法,这个方法是用来拿到“原来的值”的内存地址,返回值是valueOffset。另外 value 是一个volatile变量,在内存中可见,因此 JVM 可以保证任何时刻任何线程总能拿到该变量的最新值。


2、Unsafe 类

2.1 介绍

  实际上Atomic包里的类基本都是使用Unsafe实现的包装类。也就是上面的原子类实现过程中都会用到Unsafe类。Java中的Unsafe类提供了类似C++手动管理内存的能力。Unsafe类,全限定名是sun.misc.Unsafe,从名字可以看出来这个类对普通程序员来说是“危险”的,一般应用开发者不会用到这个类。Unsafe类是"final"的,不允许继承。且构造函数是private的,无法在外部对其进行实例化。

public final class Unsafe
{
private static final Unsafe theUnsafe;
public static final int INVALID_FIELD_OFFSET = -1;
private static native void registerNatives();
// 构造函数是private的,不允许外部实例化
private Unsafe(){
}
@CallerSensitive
public static Unsafe getUnsafe(){
Class var0 = Reflection.getCallerClass();
// 仅在引导类加载器`BootstrapClassLoader`加载时才合法
if(!VM.isSystemDomainLoader(var0.getClassLoader())){
throw new SecurityException("Unsafe");
}
else{
return theUnsafe;
}
}
}


那如若想使用这个类,该如何获取其实例?有如下两个可行方案。


 2.2 如何使用 Unsafe 类


(1)从getUnsafe方法的使用限制条件出发,通过Java命令行命令-Xbootclasspath/a 把调用Unsafe相关方法的类A所在jar包路径追加到默认的bootstrap路径中,使得A被引导类加载器加载,从而通过Unsafe.getUnsafe方法安全的获取Unsafe实例。

  java -Xbootclasspath/a: ${path} // 其中path为调用Unsafe相关方法的类所在jar包路径。



(2)通过反射来获得Unsafe


public Unsafe getUnsafe() throws IllegalAccessException {
try{
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
return unsafe;
}
catch (Exception e){
log.error(e.getMessage(), e);
return null;
}
}


2.3 Unsafe 的 主要功能

技术图片

 

 

 

原文链接:https://www.cnblogs.com/liujiarui/p/12811444.html


推荐阅读
  • 本文探讨为何Request对象的外观设计被认为是精妙的,重点在于其如何利用门面模式确保数据安全,同时保持系统的高效交互。 ... [详细]
  • java datarow_DataSet  DataTable DataRow 深入浅出
    本篇文章适合有一定的基础的人去查看,最好学习过一定net编程基础在来查看此文章。1.概念DataSet是ADO.NET的中心概念。可以把DataSet当成内存中的数据 ... [详细]
  • Java虚拟机及其发展历程
    Java虚拟机(JVM)是每个Java开发者日常工作中不可或缺的一部分,但其背后的运作机制却往往显得神秘莫测。本文将探讨Java及其虚拟机的发展历程,帮助读者深入了解这一关键技术。 ... [详细]
  • 本文档旨在提供C语言的基础知识概述,涵盖常量、变量、数据类型、控制结构及函数定义等内容。特别强调了常量的不同类型及其在程序中的应用,以及如何正确声明和使用函数。 ... [详细]
  • 本文探讨了Android系统中联系人数据库的设计,特别是AbstractContactsProvider类的作用与实现。文章提供了对源代码的详细分析,并解释了该类如何支持跨数据库操作及事务处理。源代码可从官方Android网站下载。 ... [详细]
  • 本文详细介绍了PHP中的几种超全局变量,包括$GLOBAL、$_SERVER、$_POST、$_GET等,并探讨了AJAX的工作原理及其优缺点。通过具体示例,帮助读者更好地理解和应用这些技术。 ... [详细]
  • 本文探讨了一个Web工程项目的需求,即允许用户随时添加定时任务,并通过Quartz框架实现这些任务的自动化调度。文章将介绍如何设计任务表以存储任务信息和执行周期,以及如何通过一个定期扫描机制自动识别并加载新任务到调度系统中。 ... [详细]
  • Web开发实践:创建连连看小游戏
    本文详细介绍了如何在Web环境中开发一款连连看小游戏,适合初学者和技术爱好者参考。通过本文,您将了解游戏的基本结构、连线算法以及实现方法。 ... [详细]
  • 探讨多种方法来确定Java对象的实际类型,包括使用instanceof关键字、getClass()方法等。 ... [详细]
  • Java高级工程师学习路径及面试准备指南
    本文基于一位朋友的PDF面试经验整理,涵盖了Java高级工程师所需掌握的核心知识点,包括数据结构与算法、计算机网络、数据库、操作系统等多个方面,并提供了详细的参考资料和学习建议。 ... [详细]
  • selenium通过JS语法操作页面元素
    做过web测试的小伙伴们都知道,web元素现在很多是JS写的,那么既然是JS写的,可以通过JS语言去操作页面,来帮助我们操作一些selenium不能覆盖的功能。问题来了我们能否通过 ... [详细]
  • 本文由公众号【数智物语】(ID: decision_engine)发布,关注获取更多干货。文章探讨了从数据收集到清洗、建模及可视化的全过程,介绍了41款实用工具,旨在帮助数据科学家和分析师提升工作效率。 ... [详细]
  • 深入解析 C++ 中的 String 和 Vector
    本文详细介绍了 C++ 编程语言中 String 和 Vector 的使用方法及特性,旨在帮助开发者更好地理解和应用这两个重要的容器。 ... [详细]
  • HDU 2537 键盘输入处理
    题目描述了一个名叫Pirates的男孩想要开发一款键盘输入软件,遇到了大小写字母判断的问题。本文提供了该问题的解决方案及实现方法。 ... [详细]
  • 本文总结了 #define 在 C/C++ 编程中的多种用途和技巧,包括定义常量、函数、宏以及条件编译等,并提供了详细的示例和注意事项。 ... [详细]
author-avatar
pilishen
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有