精华内容
下载资源
问答
  • Java原子变量

    2021-02-26 11:29:35
    为了提升性能,Java引入了原子变量,通过无锁算法(lock-free)实现多线程安全,比如CAS。原子变量只是实现多线程安全的一个手段,在对单个共享变量进行”读取-修改-写入“操作的场景下很适合,所以,...

    概述

    多个线程操作共享变量(Java堆内存上的数据)会带来bug,Java提供了锁机制(Lock)来管理多线程并发,比如synchronized,但是会带来额外的性能开销(线程阻塞,上下文切换等)。为了提升性能,Java引入了原子变量,通过无锁算法(lock-free)实现多线程安全,比如CAS。

    原子变量只是实现多线程安全的一个手段,在对单个共享变量进行”读取-修改-写入“操作的场景下很适合,所以,其适用场景没有synchronized广泛。

    多线程问题

    首先,实现一个计数器,代码如下:

    public class Counter {

    private volatile int num;

    public void increment() {

    num++;

    }

    public static void main(String[] args) {

    Counter counter = new Counter();

    // 多线程递增计数器

    IntStream.range(0, 100).parallel().forEach(i -> counter.increment());

    // 打印结果

    System.out.println("counter: " + counter.num);

    }

    }

    多次运行上述代码,打印出来的值不是100,而是98,97等。

    这是一个典型的多线程问题,num++ 看似一行简单的代码,像是一个原子操作,其实则不然,递增操作可能会三个步骤进行:

    读取当前num变量的值

    执行num+1

    将+1后的值赋值给num变量

    所以,多个线程更新后的值会出现覆盖的情况,比如两个线程同时拿到了num的值为50,在各自的线程中执行加法操作后为51,然后更新主存中的值为51,但是我们期望的值是52。

    通过synchronized解决

    给increment()方法增加synchronized关键字,如下:

    // ...

    public synchronized void increment() {

    num++;

    }

    // ...

    synchronized是Java中最常用的锁,保证被“监控”代码块在同一个时刻只能由一个线程执行,所以最终出来的结果为100,正确。

    但是,该方法会导致没获取锁的线程挂起,发生上下文切换,这就是重量级锁带来的性能开销。

    通过原子变量AtomicInteger解决

    atomic包下有AtomicInteger类,可以解决上述问题,代码如下:

    public class Counter {

    private AtomicInteger num = new AtomicInteger(0);

    public void increment() {

    while (true) {

    int oldValue = num.get();

    int newValue = oldValue + 1;

    if (num.compareAndSet(oldValue, newValue)) {

    return;

    }

    }

    }

    public static void main(String[] args) {

    Counter counter = new Counter();

    // 多线程递增计数器

    IntStream.range(0, 100).parallel().forEach(i -> counter.increment());

    // 打印结果

    System.out.println("counter: " + counter.num);

    }

    }

    运行代码,输出结果100。

    CAS原子操作

    Java并发包下的原子变量利用了CAS机制,实现了原子操作。这儿说的原子操作,是指CPU对某一块内存的原子操作(Atomic memory operation),具备如下特点:

    串行化多个线程对同一块内存的更新操作(保证多线程更新数据时的安全)。

    读取-修改-写入这三个操作不可被中断,更新操作要不然成功,要不然失败,不会出现中间状态(保证数据完整性)。

    只有当内存中的值与期望值相同时,才会执行更新操作(保证正确的逻辑)。

    在并发编程中,CAS属于”乐观锁“,假设多线程竞争几率很小,或者在很短的时间内竞争状态会结束,如果多线程竞争非常频繁,会使CPU长时间空转(busy waiting),造成资源浪费。所以,没有银弹!根据场景选择技术方案。

    CAS(Compare And Swap)需要特定的CPU指令支持,所以并不是所有硬件平台都支持CAS。Java跨平台的特性要求API的行为一致性,所以在不支持CAS的硬件平台上,atomic会退化成重量级锁。

    总结

    实现多线程的手段很多,根据场景选择合理的技术方案可以提升程序的性能。本文简单讲述了Java中原子变量是如何解决多线程问题,以及CAS的一些概念。

    展开全文
  • 原子化服务未来展望 我们从ios14 widget的特性对比分析一下,鸿蒙OS服务卡片未来可能会推出哪些功能。 1) 配置功能 用户可以根据自己的偏好配置。以天气类组件为例,有些用户可能关心的是晴天、雨天、温度等信息,...

    引言

    2021年6月2日晚间,华为在HarmonyOS 2系统及全场景新品发布会上正式推出了服务卡片,颠覆了人们对APP信息展示的认知,引起了行业内的极大关注,本文是对HarmonyOS服务卡片的原理和架构的分析。限于当前资料有限,文章内容难免有错漏,敬请谅解。

    1.HarmonyOS服务卡片简介

    服务卡片官方定义
    服务卡片(以下简称“卡片”)是鸿蒙FA(Feature Ability)的一种界面展示形式,将FA的重要信息或操作前置到卡片,以达到服务直达,减少体验层级目的。

    举例说明什么是服务卡片

    我们以“玩机技巧”这个应用为例感受服务卡片带给我们的价值。当我们用手指按下图标的同时往上滑,就会弹出该应用的默认卡片,点击卡片右上角的图钉,就将卡片固定在了桌面上;点击卡片中的按钮,可以开始查看玩机技巧。这样,通过与卡片进行交互,用户无需打开应用,就可以实现应用内的部分操作,使用十分便捷。
    在这里插入图片描述

    服务卡片的价值

    举一反三,想象一下:
    不用打开微信就可以直接运行扫一扫、付款码;
    不用打开微博就可以看到最新的热点信息;
    不用打开邮件服务就可以看到最新的邮件列表;
    ……
    服务卡片重新打开了应用创新的大门,给应用带来了新的业务价值和流量入口。

    服务卡片与原子化服务是什么关系?

    说起服务卡片,就不得不提到与之紧密关联的原子化服务。原子化服务官方是HarmonyOS 提供的一种面向未来的服务提供方式,是有独立入口的(用户可通过点击、碰一碰、扫一扫等方式直接触发)、免安装的(无需显式安装,由系统程序框架后台安装后即可使用)、可为用户提供一个或多个便捷服务的用户程序形态。服务卡片是鸿蒙OS原子化服务的展示方式。原子化服务是里子,服务卡片是面子。
    服务卡片应用当前仅支持部署在HarmonyOS闭源版本上,在鸿蒙开源版本OpenHarmony 2.0上该特性尚未支持。

    2.服务卡片操作说明

    如何查看某个应用的服务卡片

    如果应用的图标下方显示了一条横线,用手指按下图标的同时往上滑,就会弹出该应用的默认卡片,点击卡片右上角的图钉,就将卡片固定在了桌面上;卡片支持点击交互,用户无需打开应用,就可以实现应用内的部分操作。
    比如,下图中的拍照、电话、畅连应用都支持服务卡片特性。
    在这里插入图片描述

    如何查看一个应用的所有卡片?

    以“玩机技巧”这个应用为例,在桌面上长按其图标,在弹出的菜单中点击“服务卡片”,就显示出了玩机技巧这个应用的所有卡片。
    在这里插入图片描述

    如何查看服务卡片列表?

    手指从桌面左下角或右下角向屏幕中心划出,调出“我的服务”,可以看到手机支持的服务卡片列表。
    在这里插入图片描述

    3.服务卡片原理分析

    通过上面的介绍,我们对服务卡片有了大致的了解。那么服务卡片本质上到底是什么,它是类似微信小程序的应用吗?它和目前市面上的哪类应用是类似的?区别又在哪里?
    要回答上述问题,我们把业界出现的典型应用类型和典型代表简单总结一下:

    典型应用技术特征典型代表
    原生APPiOS app,android app
    H5
    混合APP原生和H5的混合体
    WidgetiOS widget
    小程序Webview渲染微信小程序
    快应用原生渲染
    轻应用具备Webapp的可被检索与智能分发的特性百度应用

    下面重点介绍一下微信小程序、快应用、widget。

    微信小程序

    微信小程序于2017年1月9日凌晨正式上线。微信小程序是一种不需要下载安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或者搜一下即可打开应用。也体现了“用完即走”的理念,用户不用关心是否安装太多应用的问题。
    微信小程序的框架包含两部分View视图层、App Service逻辑层,View层用来渲染页面结构,AppService层用来逻辑处理、数据请求、接口调用,它们在两个线程里运行。视图层使用WebView渲染,逻辑层使用JSCore运行。视图层和逻辑层通过系统层的JSBridage进行通信,逻辑层把数据变化通知到视图层,触发视图层页面更新,视图层把触发的事件通知到逻辑层进行业务处理。

    在这里插入图片描述

    快应用

    快应用是九大手机厂商基于硬件平台共同推出的新型应用生态。用户无需下载安装,即点即用,享受原生应用的性能体验。2018年3月20日在北京推出“快应用”标准。
    “快应用”使用前端技术栈开发,原生渲染,同时具备H5页面和原生应用的双重优点。

    什么是Widget?

    Widget的定位其实相当于应用程序的扩展程序,使用的关键点在于用户可以在不打开应用、无需加载等待的情况下,在屏幕上快速获取信息甚至进行简单的操作。苹果多次强调Widget不是进入应用的另一种快捷方式,Widget是一种的信息展现方式,用来快速提供展示某些用户关心的应用程序数据。Widget在刚进入中国的时候,没有通用的译名,由当时的中搜命名为“微件”。直到这次iOS 14才使用“小组件”的命名。
    在这里插入图片描述

    Widget按照用户使用场景的不同,可以分为:信息小组件、集合小组件、控件小组件及混合小组件。而iOS 一直将主屏幕的控制放置于控制中心中进行交互,因此小组件类型的主要是信息小组件及集合小组件。
    在这里插入图片描述

    Widget 的刷新完全由 WidgetCenter 控制。开发者无法通过任何 API 去主动刷新 Widget 的页面,只能告知 WidgetCenter,Timeline 需要刷新了。Widget 只能用 SwiftUI 来进行开发,确切的说,Widget 的本质是一个随着时间线而更新的 SwiftUI 视图。
    在这里插入图片描述

    widget交互及展示

    Widget的UI是无状态的,它不支持播放动画gif、视频,不支持滚动,不支持主动刷新视图,唯一支持的只有用户点击和DeepLink唤起主app。

    综合对比相关特性能力,鸿蒙卡片服务更像是对标widget的应用形态。鸿蒙服务卡片的英文名为service widget,也从侧面印证了这个观点。

    4.服务卡片特征

    鸿蒙OS服务卡片有三大特征。

    1) 随处可及

    • 服务发现:原子化服务可在服务中心发现并使用。
    • 智能推荐:原子化服务可以基于合适场景被主动推荐给用户使用;用户可在服务中心和小艺建议中发现系统推荐的服务。

    2) 服务直达

    • 原子化服务支持免安装使用。
    • 服务卡片:支持用户无需打开原子化服务便可获取服务内重要信息的展示和动态变化,如天气、关键事务备忘、热点新闻列表。

    3) 跨设备

    • 原子化服务支持运行在1+8+N设备上,如手机、平板等设备。
    • 支持跨设备分享:例如接入华为分享后,用户可分享原子化服务给好友,好友确认后打开分享的服务。
    • 支持跨端迁移:例如手机上未完成的邮件,迁移到平板继续编辑。
    • 支持多端协同:例如手机用作文档翻页和批注,配合智慧屏显示完成分布式办公;手机作为手柄,与智慧屏配合玩游戏。

    根据以上官方宣传可见,基于鸿蒙分布式能力,鸿蒙OS在widget的基础上新增了跨设备能力,赋予了widget新的生命力。
    当用户跨设备进行流转和分享业务时,被流转到的设备不用预先安装应用,极大增强了服务卡片的适用场景和价值。

    5.原子化服务架构

    关于鸿蒙OS原子化服务的架构有2张图可以参考。
    在这里插入图片描述
    在这里插入图片描述

    基本概念
    • 卡片使用方

    显示卡片内容的宿主应用,控制卡片在宿主中展示的位置。

    • 卡片管理服务

    用于管理系统中所添加卡片的常驻代理服务,包括卡片对象的管理与使用,以及卡片周期性刷新等。

    • 卡片提供方

    提供卡片显示内容的HarmonyOS应用或原子化服务,控制卡片的显示内容、控件布局以及控件点击事件。

    说明

    卡片使用方和提供方不要求常驻运行,在需要添加/删除/请求更新卡片时,卡片管理服务会拉起卡片提供方获取卡片信息。

    卡片管理服务包含以下模块:

    • 周期性刷新:在卡片添加后,根据卡片的刷新策略启动定时任务周期性触发卡片的刷新。
    • 卡片缓存管理:在卡片添加到卡片管理服务后,对卡片的视图信息进行缓存,以便下次获取卡片时可以直接返回缓存数据,降低时延。
    • 卡片生命周期管理:对于卡片切换到后台或者被遮挡时,暂停卡片的刷新;以及卡片的升级/卸载场景下对卡片数据的更新和清理。
    • 卡片使用方对象管理:对卡片使用方的RPC对象进行管理,用于使用方请求进行校验以及对卡片更新后的回调处理。
    • 通信适配层:负责与卡片使用方和提供方进行RPC通信。

    卡片提供方包含以下模块:

    • 卡片服务:由卡片提供方开发者实现,开发者实现onCreateForm、onUpdateForm和onDeleteForm处理创建卡片、更新卡片以及删除卡片等请求,提供相应的卡片服务。
    • 卡片提供方实例管理模块:由卡片提供方开发者实现,负责对卡片管理服务分配的卡片实例进行持久化管理。
    • 通信适配层:由HarmonyOS SDK提供,负责与卡片管理服务通信,用于将卡片的更新数据主动推送到卡片管理服务。

    根据以上架构描述,个人分析和推理的内容如下。

    服务卡片如何做到跨设备流转和分享时不用预先安装应用?

    鸿蒙OS原子化服务采用卡片使用方和卡片提供方分离的架构,卡片使用方和卡片提供方可以在相同的或不同的设备上。如果在不同的设备进行流转,通过RPC通信,鸿蒙OS可以实现跨设备流转和分享能力,并且接收方不用预先安装应用。
    同时,对于卡片提供方离线的风险,鸿蒙OS通过在架构上支持卡片管理服务的缓存机制也进行了有效应对。

    其他设计讨论

    目前尚不清楚原子化服务定时刷新模块的实现原理,不知道是否和iOS widget相同,由系统统一调度刷新,从而提高整机刷新性能。
    当卡片使用方和卡片提供方在同一台终端上时,从架构上看,似乎可以优化为直接通信不经过卡片管理服务的方式,中间减少一个环节,避免性能损耗。

    6.原子化服务未来展望

    我们从ios14 widget的特性对比分析一下,鸿蒙OS服务卡片未来可能会推出哪些功能。

    1) 配置功能

    用户可以根据自己的偏好配置。以天气类组件为例,有些用户可能关心的是晴天、雨天、温度等信息,有些用户可能只关心PM2.5的信息,由于小组件的显示空间有限,有时候你无法将所有的信息都展示在组件内,因此让用户选择他感兴趣的信息进行小组件的配置是非常重要的特性。

    2) 类似Smart Stack功能

    iOS widget具有智能堆栈 Smart Stack能力 ,集成siri的智能化推荐能力,能根据你使用时间,位置等因素,来智能显示组件。比如,早上起床显示天气信息;到达办公室显示微信新消息信息;晚上下班显示路线拥堵情况等。目前鸿蒙OS实现了小艺建议,但是小艺建议推荐的是应用列表,不是服务卡片的轮流展示能力。

    3) 展开和折叠功能

    服务卡片的展开和折叠能力,对于列表类的服务卡片显得尤为重要,折叠时可以节省桌面空间,对于部分对空间敏感的人群特别适用。

    7.原子化服务实例

    大家可以参考华为codelab,进行原子化服务的应用开发:
    时钟FA卡片开发样例
    https://developer.huawei.com/consumer/cn/codelabsPortal/carddetails/Clock-Card
    在这里插入图片描述
    本人更多内容请参考鸿蒙OS精品资料整理,持续更新中

    展开全文
  • 案例说明 volatile 和原子类的异同 我们首先看一个案例。如图所示,我们两个线程。 在图中左上角可以看出,一个公共的 boolean flag 标记位,最开始赋值为 true,然后线程 2 会进入一个 while 循环,并且根据这...
    案例说明 volatile 和原子类的异同

    我们首先看一个案例。如图所示,我们有两个线程。
    在这里插入图片描述
    在图中左上角可以看出,有一个公共的 boolean flag 标记位,最开始赋值为 true,然后线程 2 会进入一个 while 循环,并且根据这个 flag 也就是标记位的值来决定是否继续执行或着退出。

    最开始由于 flag 的值是 true,所以首先会在这里执行一定时期的循环。然后假设在某一时刻,线程 1 把这个 flag 的值改为 false 了,它所希望的是,线程 2 看到这个变化后停止运行。

    但是这样做其实是有风险的,线程 2 可能并不能立刻停下来,也有可能过一段时间才会停止,甚至在最极端的情况下可能永远都不会停止。

    为了理解发生这种情况的原因,我们首先来看一下 CPU 的内存结构,这里是一个双核的 CPU 的简单示意图:

    在这里插入图片描述
    可以看出,线程 1 和线程 2 分别在不同的 CPU 核心上运行,每一个核心都有自己的本地内存,并且在下方也有它们共享的内存。

    最开始它们都可以读取到 flag 为 true ,不过当线程 1 这个值改为 false 之后,线程 2 并不能及时看到这次修改,因为线程 2 不能直接访问线程 1 的本地内存,这样的问题就是一个非常典型的可见性问题。

    在这里插入图片描述
    要想解决这个问题,我们只需要在变量的前面加上 volatile 关键字修饰,只要我们加上这个关键字,那么每一次变量被修改的时候,其他线程对此都可见,这样一旦线程 1 改变了这个值,那么线程 2 就可以立刻看到,因此就可以退出 while 循环了。
    在这里插入图片描述
    之所以加了关键字之后就就可以让它拥有可见性,原因在于有了这个关键字之后,线程 1 的更改会被 flush 到共享内存中,然后又会被 refresh 到线程 2 的本地内存中,这样线程 2 就能感受到这个变化了,所以 volatile 这个关键字最主要是用来解决可见性问题的,可以一定程度上保证线程安全。

    现在让我们回顾一下很熟悉的多线程同时进行 value++ 的场景,如图所示:
    在这里插入图片描述
    如果它被初始化为每个线程都加 1000 次,最终的结果很可能不是 2000。由于 value++ 不是原子的,所以在多线程的情况下,会出现线程安全问题。但是如果我们在这里使用 volatile 关键字,能不能解决问题呢?
    在这里插入图片描述
    很遗憾,答案是即便使用了 volatile 也是不能保证线程安全的,因为这里的问题不单单是可见性问题,还包含原子性问题。

    我们有多种办法可以解决这里的问题,第 1 种是使用 synchronized 关键字,如图所示:
    在这里插入图片描述
    这样一来,两个线程就不能同时去更改 value 的数值,保证!](https://img-
    value++ 语句的原子性,并且 synchronized 同样保证了可见性,也就是说,当第 1 个线程修改了 value 值之后,第 2 个线程可以立刻看见本次修改的结果。

    解决这个问题的第 2 个方法,就是使用我们的原子类,如图所示:
    在这里插入图片描述
    比如用一个 AtomicInteger,然后每个线程都调用它的 incrementAndGet 方法。

    在利用了原子变量之后就无需加锁,我们可以使用它的 incrementAndGet 方法,这个操作底层由 CPU 指令保证原子性,所以即便是多个线程同时运行,也不会发生线程安全问题。

    原子类和 volatile 的使用场景

    那下面我们就来说一下原子类和 volatile 各自的使用场景。

    我们可以看出,volatile 和原子类的使用场景是不一样的,如果我们有一个可见性问题,那么可以使用 volatile 关键字,但如果我们的问题是一个组合操作,需要用同步来解决原子性问题的话,那么可以使用原子变量,而不能使用 volatile 关键字。

    通常情况下,volatile 可以用来修饰 boolean 类型的标记位,因为对于标记位来讲,直接的赋值操作本身就是具备原子性的,再加上 volatile 保证了可见性,那么就是线程安全的了。

    而对于会被多个线程同时操作的计数器 Counter 的场景,这种场景的一个典型特点就是,它不仅仅是一个简单的赋值操作,而是需要先读取当前的值,然后在此基础上进行一定的修改,再把它给赋值回去。这样一来,我们的 volatile 就不足以保证这种情况的线程安全了。我们需要使用原子类来保证线程安全。

    展开全文
  • Java线程安全-原子

    2021-02-12 22:46:52
    什么是原子性如果把一个事务可看作是一个程序,它要么完整的被执行,要么完全不执行。这种特性就叫原子性问题1public class Counter {volatile int i = 0;public void add() {i++;}}public class Demo1_CounterTest {...

    什么是原子性

    如果把一个事务可看作是一个程序,它要么完整的被执行,要么完全不执行。这种特性就叫原子性

    问题1

    public class Counter {

    volatile int i = 0;

    public void add() {

    i++;

    }

    }

    public class Demo1_CounterTest {

    public static void main(String[] args) throws InterruptedException {

    final Counter ct = new Counter ();

    // 开启10个线程对Counter对象中的i进行累加

    for (int i = 0; i < 10; i++) {

    new Thread(new Runnable() {

    @Override

    public void run() {

    for (int j = 0; j < 10000; j++) {

    ct.add();

    }

    System.out.println("done...");

    }

    }).start();

    }

    Thread.sleep(6000L);

    System.out.println(ct.i);

    // 无法达到预期输出结果 100000

    }

    }

    以上代码虽然对实现了变量 i 的可见性,但是并没有实现对 i 的原子操作。其他线程都能读到 i ,但读取过后 i 又发生改变,就会导致读取的 i 是一个失效的值,从而引发原子性问题

    原子操作

    原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可以被打乱,也不可以被切割而只执行其中一部分。

    将整个操作视作为一个整体,资源在该次操作中保持一致,这是原子性的核心特征

    解决原子性问题

    Atomic 原子类

    import java.util.concurrent.atomic.AtomicInteger;

    public class Counter {

    // 使用原子类

    AtomicInteger i = new AtomicInteger(0);

    public void add() {

    i.incrementAndGet();

    }

    }

    synchronized 同步关键字

    public class Counter {

    volatile int i = 0;

    // 加入同步关键字,即可实现线程安全同步锁,一个线程执行完了才能执行下一个线程

    public synchronized void add() {

    i++;

    }

    }

    Lock 锁

    import java.util.concurrent.locks.Lock;

    import java.util.concurrent.locks.ReentrantLock;

    public class Counter {

    volatile int i = 0;

    // 加入锁,在同一时间只会有一个线程抢到锁

    Lock lock = new ReentrantLock();

    public void add() {

    lock.lock();

    try {

    i++;

    }finally {

    lock.unlock();

    }

    }

    }

    CAS(Compare and swap)

    Compare and swap 比较和交换。属于硬件同步原语,处理器提供了基本内存操作的原子性保证

    CAS操作需要输入两个数值,一个旧值(期望操作前的值)和一个新值,在操作期间先对旧值进行比较,若没有发生变化,才交换成新的值,发生了变化则不交换

    Java中的sun.misc.Unsafe类,提供了compareAndSwaplnt() 和 compareAndSwapLong() 等几个方法实现CAS

    b4af0271be54?utm_campaign=hugo

    cas操作原理,两个线程同时修改

    CAS操作会用原来的值进行比较,比较后再设置新的值。如果发现比较的值不对,则本次操作失败。进入自旋(重新再执行)

    模拟CAS操作

    public class Counter {

    volatile int i = 0;

    private static Unsafe unsafe = null;

    private static long valueOffset;

    static {

    //unsafe = Unsafe.getUnsafe(); // JDK不提供,通过反射来实现

    try{

    Field field = Unsafe.class.getDeclaredField("theUnsafe");

    field.setAccessible(true);

    unsafe = (Unsafe) field.get(null);

    //获取i字段的offset

    Field iField = Counter.class.getDeclaredField("i");

    valueOffset = unsafe.objectFieldOffset(iField);

    } catch (NoSuchFieldException e) {

    e.printStackTrace();

    } catch (IllegalAccessException e) {

    e.printStackTrace();

    }

    }

    public void add() {

    while(true) {

    // 拿到i字段的当前值

    int current = unsafe.getIntVolatile(this, valueOffset);

    // 用CAS操作将i加1

    if (unsafe.compareAndSwapInt(this, valueOffset, current, current+1)) {

    break;

    }

    }

    }

    }

    AtomicInteger内部实现的就是CAS原子性操作

    J.U.C包内的原子操作封装类

    类名

    解释

    AtomicBoolean

    原子更新布尔类型

    AtomicInteger

    原子更新整型

    AtomicLong

    原子更新长整型

    AtomicIntegerArray

    原子更新整型数组里的元素

    AtomicLongArray

    原子更新长整型数组里的元素

    AtomicReferenceArray

    原子更新引用类型数组里的元素

    AtomicIntegerFieldUpdater

    原子更新整型字段的更新器

    AtomicLongFieldUpdater

    原子更新长整型字段的更新器

    AtomicReferenceFieldUpdater

    原子更新引用类型的字段

    AtomicReference

    原子更新引用类型

    AtomicStampedReference

    原子更新带有版本号的引用类型

    AtomicMarkableReference

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

    1.8更新:计数器增强版,高并发下性能更好

    原理:分成多个单元,不同线程更新不同的单元,只有需要汇总的时候才计算所有单元的操作

    DoubleAccumulator

    更新器

    LongAccumulator

    更新器

    DoubleAdder

    计数器

    LongAdder

    计数器

    LongAccumulator示例

    import java.util.concurrent.atomic.LongAccumulator;

    public class Demo_LongAccumulator {

    public static void main(String[] args) throws InterruptedException {

    /*

    LongAccumulator 可以帮我们做到自定义的累加计算

    第一个参数为lambda方法,y表示状态值,x表示每次传入的值

    第二个参数为状态值,(这里传入0,则y一开始等于0)

    */

    LongAccumulator accumulator = new LongAccumulator(

    (y,x)->{

    System.out.println("x:" + x + ",y:" + y);

    // 自定义累加逻辑 (这里为:x + y)

    return x + y;

    },

    0L);

    for (int i = 0; i < 3; i++) {

    // 把1传入到 LongAccumulator 中

    accumulator.accumulate(1);

    }

    System.out.println("result=" + accumulator.get());

    }

    }

    LongAdder示例

    import java.util.concurrent.atomic.LongAdder;

    public class Demo_LongAdder {

    public static void main(String[] args) throws InterruptedException {

    /*

    LongAdder类与AtomicLong类的区别在于

    高并发时前者将对单一变量的CAS操作

    分散为对数组cells中多个元素的CAS操作,取值时进行求和;

    而在并发较低时仅对base变量进行CAS操作,与AtomicLong类原理相同

    */

    LongAdder lacount = new LongAdder();

    for (int i = 0; i < 6; i++) {

    new Thread(() -> {

    long starttime = System.currentTimeMillis();

    while (System.currentTimeMillis() - starttime < 2000) { // 运行两秒

    //increment()方法就是对add(long x)的封装

    lacount.increment();

    }

    long endtime = System.currentTimeMillis();

    }).start();

    }

    Thread.sleep(3000);

    // 返回的是base和cells数组中所有元素的和,这里的base像是一个初始值的作用

    System.out.println(lacount.sum());

    }

    }

    CAS的三个问题

    循环+CAS,自旋的实现让所有线程都处于高频运行,争抢CPU执行时间的状态。如果长时间不成功,会带来很大的CPU资源消耗

    仅针对单个变量的操作,不能用于多个变量来实现原子操作

    ABA问题。

    ABA问题

    b4af0271be54?utm_campaign=hugo

    ABA问题

    线程1、线程2同时读取到i=0后

    线程1、线程2都要执行CAS操作

    假设线程2操作稍后于线程1、则线程1执行成功,线程2执行失败

    但紧接着线程1又执行了CAS(1,0),将i的值改回0,此时线程2执行,引发ABA问题

    AtomicStampedReference 加入版本号的数据比较更新

    // 存储在栈里面元素 -- 对象

    public class Node {

    public final String value;

    public Node next;

    public Node(String value) {

    this.value = value;

    }

    @Override

    public String toString() {

    return "value=" + value;

    }

    }

    import java.util.concurrent.atomic.AtomicStampedReference;

    import java.util.concurrent.locks.LockSupport;

    public class ConcurrentStack {

    // top cas无锁修改

    //AtomicReference top = new AtomicReference();

    AtomicStampedReference top =

    new AtomicStampedReference<>(null, 0);

    public void push(Node node) { // 入栈

    Node oldTop;

    int v;

    do {

    v = top.getStamp();

    oldTop = top.getReference();

    node.next = oldTop;

    }

    while (!top.compareAndSet(oldTop, node, v, v+1)); // CAS 替换栈顶

    }

    // 出栈 -- 取出栈顶 ,为了演示ABA效果, 增加一个CAS操作的延时

    public Node pop(int time) {

    Node newTop;

    Node oldTop;

    int v;

    do {

    v = top.getStamp();

    oldTop = top.getReference();

    if (oldTop == null) { //如果没有值,就返回null

    return null;

    }

    newTop = oldTop.next;

    if (time != 0) { //模拟延时

    LockSupport.parkNanos(1000 * 1000 * time); // 休眠指定的时间

    }

    }

    while (!top.compareAndSet(oldTop, newTop, v, v+1)); //将下一个节点设置为top

    return oldTop; //将旧的Top作为值返回

    }

    }

    展开全文
  • 可事实却并不是你想的那样,不管你运行多少次,每次输出的结果都会不一样,而这些输出结果都一个特点是,都小于 200 万。 以下是执行三次的结果 1459782 1379891 1432921 这种现象就是线程不安全,究其根因,其实...
  • 原子变量类Atomic*

    2021-01-09 12:16:43
    原子变量类详细介绍
  • 支持原子数据定义语句MySQL 8.0支持原子数据定义语言(DDL)语句。这个特性被称为原子DDL。原子DDL语句将与DDL操作相关联的数据字典更新、存储引擎操作和二进制日志写入合并到单个原子操作中。该操作要么已提交,并将...
  • Redis 原子性理解

    2021-07-19 08:17:51
    所谓原子操作是指不会被线程调度机制打断的操作 (说人话 : 两个线程之间的操作互不影响,每个操作都是独立的线程) 单线程中,能够在单条指令中完成的操作都可以认为是"原子操作",因为终端只能发生于指令之间 在多...
  • (2)原子操作和数据库的ACID啥关系?(3)AtomicInteger是怎么实现原子操作的?(4)AtomicInteger是什么缺点?简介AtomicInteger是java并发包下面提供的原子类,主要操作的是int类型的整型,通过调用底层Unsafe的CAS...
  • 在并发编程中很容易出现并发安全的问题,一个很简单的例子就是多线程更新变量i=1,比如多个线程执行i++操作,就可能获取不到正确的值,而这个问题,最常用的方法是通过Synchronized进行控制来达到线程安全的目的...
  • 原子的compareAndSet方法也内存一致性特点,就像应用到整型原子变量中的简单原子算法。 为了看看这个包如何使用,让我们返回到最初用于演示线程干扰的Counter类: class Counter { private int c = 0; public void...
  • 如何保证原子

    2021-07-21 20:55:48
    synchronized是独占锁,并不能改变CPU时间切换的特点,只有当其他线程访问资源时,发现锁未被释放,只能等待. synchronized一定能保证原子性,因为被其修饰的某段代码,只能由一个线程执行,所以一定可以保证原子操作. JUC...
  • Redis 事务是否具备原子性?
  • 《固体物理 03-03一维双原子链》由会员分享,可在线阅读,更多相关《固体物理 03-03一维双原子链(35页珍藏版)》请在人人文库网上搜索。1、固体物理Solid State Physics, 3.3 一维双原子链,第三章 晶格振动,3.3 一维...
  • 事务四大特征原子性,一致性,隔离性和持久性 1.原子性(Atomicity) 一个原子事务要么完整执行,要么干脆不执行。这意味着,工作单元中的每项任务都必须正确执行。如果任一任务执行失败,则整个工作单元或事务...
  • 《HarmonyOS实战—入门到开发,浅析原子化服务》

    千次阅读 多人点赞 2021-08-03 21:18:09
    【本文正在参与“有奖征文 | HarmonyOS征文大赛”活动】 HarmonyOS操作系统   在介绍鸿蒙系统前,我们必要了解下鸿蒙系统应运而生的时代背景。近年来,我国在电子信息技术领域中愈发觉需要“独立”,资源的匮乏...
  • MySQL 8新特性--原子DDL

    2021-02-07 05:19:53
    1.Atomic DDL—原子DDL从MySQL8.0开始支持原子DDL,原子DDL语句就是将和DDL操作关联的数据字典更新,存储引擎内部操作和二进制日志写入操作组合到单个,原子事务中。即使数据库在DDL执行期间挂了,也会提交事务,并...
  • 在并发编程中,所有问题的根源就是可见性、原子性和有序性问题,这篇文章我们就来聊聊原子性问题。在介绍原子性问题之前,先来说下线程安全:线程安全我理解的线程安全就是不管单线程还是多线程并发的时候,始终能...
  • ACID 中关于原子性的定义:原子性:一个事务...那么 Redis 的事务到底符不符合原子性的特征呢?官方文档对事务的描述如下:事务可以一次执行多个命令, 并且带以下两个重要的保证:事务是一个单独的隔离...
  • java原子操作CAS

    2021-02-28 12:25:38
    所谓原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会任何线程上下文切换。原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可以被打乱,也不可以被切割而只...
  • 9.0 来自JDK官方的多线程描述JDK官方对于多线程相关理论的说明:里面介绍同步关键字、原子性、死锁等等概念。(源于官方才是原汁原味)9.1 原子性的引入9.1.1 多线程引起的问题下面跟上节一样,我们先用一个简单的...
  • 智能优化算法:原子优化算法 文章目录智能优化算法:原子优化算法1.原子优化算法原理2.实验结果3.参考文献4.Matlab代码 摘要:原子优化算法(Atom Search Optimization)是于2019提出的一种基于分子动力学模型的新颖...
  • 重点分析全球与中国市场的主要厂商产品特点、产品规格、价格、销量、销售收入及全球和中国市场主要生产商的市场份额。历史数据为2016至2020年,预测数据为2021至2027年。 主要生产商包括: Asylum research ...
  • Java中的原子

    2021-11-06 08:47:36
    原子类的作用和锁类似,是为了保证并发情况下线程安全,不过原子类相比于锁,一定的优势。 粒度更细,原子变量可以把竞争范围缩小到变量级别,这是我们可以获得的最细粒度的情况了,通常锁的粒度都要大于原子变量...
  • 原标题:新的原子分组方式预示着新的材料、药物和计算机科学家们发现了一种新的方法,将原子群连接在一起形成形状变化的分子——开辟了一个新的化学领域的可能性,开发了无数具有新特性的新药、微电子学和材料。...
  • MySQL 8.0支持原子数据定义语言(DDL)语句。此功能称为原子DDL。原子DDL语句将数据字典更新,存储引擎操作和与DDL操作相关联的二进制日志写入操作组合到单个原子操作中。即使服务器在操作过程中暂停,该操作也可以...
  • 那么目前可以给出答案了: 压缩感知的尽头, 就是 原子范数最小化算法。 而其能在一众算法中登顶的原因也很简单: 它既是拥有优良凸优化性质的算法, 又没有精度的限制。 简单而言, 如果说 OMP 等在有限码本上选取...
  • 其最大特点是用户无需下载“南方航空”App,即可获得与 App 相同的使用体验。 招行银行试着将财富管理的服务从App外延至鸿蒙系统,以App热门栏位“财富直击”为抓手,形成一个原子化服务向客户推荐,当用户看见心仪...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 133,364
精华内容 53,345
关键字:

原子有哪些特点