当前位置: 首页 > news >正文

Java——聊聊JUC中的原子变量类

文章目录:

        1.什么是原子变量类?

        2.AtomicInteger(基本类型原子变量类)

        3.AtomicIntegerArray(数组类型原子变量类)

        4.AtomicMarkableReference(引用类型原子变量类)

        5.AtomicIntegerFieldUpdater(对象Integer类型属性修改原子变量类)

        6.AtomicReferenceFieldUpdater(对象引用类型属性修改原子变量类)

        7.LongAdder、LongAccumulator(原子变量增强类)

        8.浅谈LongAdder为什么这么快?


1.什么是原子变量类?

我们参照jdk的软件包,可以看到就是在 java.util.concurrent.atomic 包下。

一共16个原子变量类,下面我来通过一些Demo简单介绍一下它们的用法。


2.AtomicInteger(基本类型原子变量类)

AtomicInteger 和 AtomicLong 以及 AtomicBoolean 都是一个类别的,都是操作单个数据,只是类型不一样(int、long、布尔)。

所以我就以AtomicInteger举例。

package com.juc.atomic;import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;/*** @author: SongZiHao* @date: 2023/2/11*/
class MyNumber {AtomicInteger atomicInteger = new AtomicInteger();public void addPlusPlus() {atomicInteger.getAndIncrement();}
}public class AtomicIntegerDemo {public static final int SIZE = 50;public static void main(String[] args) throws InterruptedException {MyNumber number = new MyNumber();CountDownLatch cdl = new CountDownLatch(SIZE); //计数器for (int i = 0; i < SIZE; i++) {new Thread(() -> {try {for (int j = 0; j < 1000; j++) {number.addPlusPlus(); //50个线程,每个线程执行1000次number++自增操作}} finally {cdl.countDown(); //每执行完一个线程,计数器减一}}, String.valueOf(i)).start();}cdl.await(); //这里阻塞等待,直到50个线程全部执行完,计数器清零,程序才会继续向下执行System.out.println(Thread.currentThread().getName() + " result: " + number.atomicInteger.get());}
}


3.AtomicIntegerArray(数组类型原子变量类)

AtomicIntegerArray 和 AtomicLongArray 以及 AtomicReferenceArray 都是一个类别的,都是操作数组类型数据,只是数组的类型不一样(int、long、引用类型)。

所以我就以 AtomicIntegerArray 举例。

package com.juc.atomic;import java.util.concurrent.atomic.AtomicIntegerArray;/*** @author: SongZiHao* @date: 2023/2/11*/
public class AtomicIntegerArrayDemo {public static void main(String[] args) {AtomicIntegerArray array = new AtomicIntegerArray(new int[5]); //0 0 0 0 0
//        AtomicIntegerArray array = new AtomicIntegerArray(5); //0 0 0 0 0
//        AtomicIntegerArray array = new AtomicIntegerArray(new int[]{1, 2, 3, 4, 5}); //1 2 3 4 5for (int i = 0; i < array.length(); i++) {System.out.println(array.get(i)); //0 0 0 0 0}int ans = 0;ans = array.getAndSet(0, 666); //先get,后setSystem.out.println(ans + ", " + array.get(0));ans = array.getAndIncrement(0); //先get,后自增(i++)System.out.println(ans + ", " + array.get(0));}
}


4.AtomicMarkableReference(引用类型原子变量类)

AtomicReference:可以带泛型,更新引用类型。

AtomicStampedReference:携带版本号的引用类型原子类,解决修改过几次的问题,可以解决ABA问题。关于这个原子变量类的Demo可以参考我的这篇文章:CAS解决ABA问题

AtomicMarkableReference:类似于AtomicStampedReference,原子更新带有标记位的引用类型对象,只是不采用版本号记录,而是采用标记位true、false。

来看下面关于AtomicMarkableReference的Demo。

package com.juc.atomic;import java.util.concurrent.atomic.AtomicMarkableReference;/*** @author: SongZiHao* @date: 2023/2/11*/
public class AtomicMarkableReferenceDemo {static AtomicMarkableReference markableReference = new AtomicMarkableReference(100, false);public static void main(String[] args) {new Thread(() -> {boolean marked = markableReference.isMarked(); //falseSystem.out.println(Thread.currentThread().getName() + " 默认标识:" + marked);try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}//1秒之后,t1线程读取值是100,和预期一样,首先将marked由false改为取反之后的值,也即truemarkableReference.compareAndSet(100, 1000, marked, !marked);}, "t1").start();new Thread(() -> {boolean marked = markableReference.isMarked(); //falseSystem.out.println(Thread.currentThread().getName() + " 默认标识:" + marked);try {Thread.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}//2秒之后,t2再次读取,值已经被改为了1000,marked也被改为了true,所以此次cas失败boolean flag = markableReference.compareAndSet(100, 2000, marked, !marked);System.out.println(Thread.currentThread().getName() + " cas-result:" + flag); //cas失败,所以是falseSystem.out.println(Thread.currentThread().getName() + " " + markableReference.isMarked()); //marked已被t1线程改为trueSystem.out.println(Thread.currentThread().getName() + " " + markableReference.getReference()); //变量值已被t1线程改为1000}, "t2").start();}
}


5.AtomicIntegerFieldUpdater(对象Integer类型属性修改原子变量类)

AtomicIntegerFieldUpdater:原子更新对象中Integer类型字段的值,该字段必须以 volatile int 修饰。

AtomicLongFieldUpdater:原子更新对象中Long类型字段的值,该字段必须以 volatile long 修饰。

AtomicReferenceFieldUpdater:原子更新引用类型字段的值,该字段必须以 volatile T 修饰。(T是引用类型的泛型值)

因为对象的属性修改类型原子类都是抽象类*,所以每次使用都必须使用静态方法newUpdater()创建一个更新器*,并且需要设置想要更新的类和属性。

下面先看 AtomicIntegerFieldUpdater 的Demo。

package com.juc.atomic;import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;/*** @author: SongZiHao* @date: 2023/2/11*/
class BankAccount {public String bankName = "CCB";public volatile int money = 0;AtomicIntegerFieldUpdater<BankAccount> fieldUpdater =AtomicIntegerFieldUpdater.newUpdater(BankAccount.class, "money");public void addMoney(BankAccount bankAccount) {fieldUpdater.getAndIncrement(bankAccount);}
}public class AtomicIntegerFieldUpdateDemo {public static void main(String[] args) throws InterruptedException {BankAccount bankAccount = new BankAccount();CountDownLatch cdl = new CountDownLatch(10); //计数器for (int i = 0; i < 10; i++) {new Thread(() -> {try {for (int j = 0; j < 1000; j++) {bankAccount.addMoney(bankAccount); //10个线程,每个线程对money执行1000次自增操作}} finally {cdl.countDown(); //每执行完一个线程,计数器减一}}, String.valueOf(i)).start();}cdl.await(); //阻塞等待,直到10个线程全部执行完,计数器清零,程序继续向下执行System.out.println(Thread.currentThread().getName() + " result: " + bankAccount.money);}
}


6.AtomicReferenceFieldUpdater(对象引用类型属性修改原子变量类)

上面介绍了AtomicIntegerFieldUpdater针对Integer类型的属性进行修改。

下面来看 AtomicReferenceFieldUpdater 如何针对引用类型的属性进行修改。

package com.juc.atomic;import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;/*** @author: SongZiHao* @date: 2023/2/11*/
class Resource {public volatile Boolean isInit = Boolean.FALSE;AtomicReferenceFieldUpdater<Resource, Boolean> fieldUpdater= AtomicReferenceFieldUpdater.newUpdater(Resource.class, Boolean.class, "isInit");public void init(Resource resource) {//cas操作,同一时刻只会有一个线程cas成功,其他线程cas失败或者自旋等待if (fieldUpdater.compareAndSet(resource, Boolean.FALSE, Boolean.TRUE)) {System.out.println(Thread.currentThread().getName() + " ---- start init, need 1 second");try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " ---- end init....");} else {System.out.println("已经有其他线程在进行初始化操作....");}}
}public class AtomicReferenceFieldUpdateDemo {public static void main(String[] args) {Resource resource = new Resource();for (int i = 0; i < 5; i++) {new Thread(() -> {resource.init(resource); //5个线程并发去修改资源类中的引用类型属性}, String.valueOf(i)).start();}}
}

由于以上两个案例都是针对某个类中的某个属性进行原子修改,而且这些属性都采用 volatile 修饰,小提一嘴:

面试官问你:你在哪里用了volatile?

  1. 在AtomicReferenceFieldUpdater中,因为是规定好的必须由volatile修饰的。
  2. 单例模式的DCL写法中,采用volatile保证单例在多线程之间的可见性。

7.LongAdder、LongAccumulator(原子变量增强类)

首先,我们来看在阿里巴巴Java开发手册中有这样一个参考内容。他说的是 LongAdder 要比传统的 AtomicLong 的性能更好,同时也会减少乐观锁的重试次数(这个很关键,因为我们都知道原子变量类的底层实现都是CAS,而CAS就是基于乐观锁机制做的)。

下面我们先看一下简单的案例。

package com.juc.atomic;import java.util.concurrent.atomic.LongAccumulator;
import java.util.concurrent.atomic.LongAdder;/*** @author: SongZiHao* @date: 2023/2/11*/
public class LongAdderDemo {public static void main(String[] args) {LongAdder longAdder = new LongAdder(); //0longAdder.increment();longAdder.increment();longAdder.increment(); //3System.out.println(longAdder.sum());LongAccumulator longAccumulator = new LongAccumulator((x, y) -> x + y, 0);longAccumulator.accumulate(1); //此时x=0,y=1,求和结果是1longAccumulator.accumulate(3); //此时x=1,y=3,求和结果是4System.out.println(longAccumulator.get()); //4}
}

上面的案例就不多说了,主要来看一下下面关于 synchronized、AtomicLong、LongAdder、LongAccumulator 在多线程并发情况下的性能对比(一目了然)。

模拟的是一个点赞器功能,50个线程,每个线程点赞100万次,最终数据一定是五千万。

package com.juc.atomic;import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.concurrent.atomic.LongAdder;/*** @author: SongZiHao* @date: 2023/2/11*/
class ClickNumber {int number = 0;public synchronized void addBySynchronized() {number++;}AtomicLong atomicLong = new AtomicLong(0);public void addByAtomicLong() {atomicLong.getAndIncrement();}LongAdder longAdder = new LongAdder();public void addByLongAdder() {longAdder.increment();}LongAccumulator longAccumulator = new LongAccumulator((x, y) -> x + y, 0);public void addByLongAccumulator() {longAccumulator.accumulate(1);}
}public class LongAccumulatorDemo {public static final int CLICK_NUMBER = 1000000;public static final int THREAD_NUMBER = 50;public static void main(String[] args) throws InterruptedException {ClickNumber clickNumber = new ClickNumber();long startTime;long endTime;CountDownLatch cdl1 = new CountDownLatch(THREAD_NUMBER);CountDownLatch cdl2 = new CountDownLatch(THREAD_NUMBER);CountDownLatch cdl3 = new CountDownLatch(THREAD_NUMBER);CountDownLatch cdl4 = new CountDownLatch(THREAD_NUMBER);//synchronizedstartTime = System.currentTimeMillis();for (int i = 0; i < THREAD_NUMBER; i++) {new Thread(() -> {try {for (int j = 0; j < CLICK_NUMBER; j++) {clickNumber.addBySynchronized();}} finally {cdl1.countDown();}}, String.valueOf(i)).start();}cdl1.await();endTime = System.currentTimeMillis();System.out.println("synchronized result: " + clickNumber.number + ", cost time: " + (endTime - startTime) + " ms....");//AtomicLongstartTime = System.currentTimeMillis();for (int i = 0; i < THREAD_NUMBER; i++) {new Thread(() -> {try {for (int j = 0; j < CLICK_NUMBER; j++) {clickNumber.addByAtomicLong();}} finally {cdl2.countDown();}}, String.valueOf(i)).start();}cdl2.await();endTime = System.currentTimeMillis();System.out.println("AtomicLong result: " + clickNumber.atomicLong.get() + ", cost time: " + (endTime - startTime) + " ms....");//LongAdderstartTime = System.currentTimeMillis();for (int i = 0; i < THREAD_NUMBER; i++) {new Thread(() -> {try {for (int j = 0; j < CLICK_NUMBER; j++) {clickNumber.addByLongAdder();}} finally {cdl3.countDown();}}, String.valueOf(i)).start();}cdl3.await();endTime = System.currentTimeMillis();System.out.println("LongAdder result: " + clickNumber.longAdder.sum() + ", cost time: " + (endTime - startTime) + " ms....");//LongAccumulatorstartTime = System.currentTimeMillis();for (int i = 0; i < THREAD_NUMBER; i++) {new Thread(() -> {try {for (int j = 0; j < CLICK_NUMBER; j++) {clickNumber.addByLongAccumulator();}} finally {cdl4.countDown();}}, String.valueOf(i)).start();}cdl4.await();endTime = System.currentTimeMillis();System.out.println("LongAccumulator result: " + clickNumber.longAccumulator.get() + ", cost time: " + (endTime - startTime) + " ms....");}
}

从结果中可以看到, 内部锁synchronized是最耗时的,因为它的锁粒度比较粗,不再多说了。AtomicLong基于CAS乐观锁,性能要好一些。而两个原子变量增强类的性能可以说在AtomicLong基础上提升了将近10倍,这如果是在高并发的场景下就很恐怖了。。。


8.浅谈LongAdder为什么这么快?

我们浅谈一下LongAdder在大并发的情况下,性能为什么这么快?

其实在小并发下情况差不多;但在高并发情况下,在AtomicLong中,等待的线程会不停的自旋,导致效率比较低;而LongAdder用cell[]分了几个块出来,最后统计总的结果值(base+所有的cell值),分散热点。

  • 内部有一个base变量,一个Cell[]数组。
  • base变量:非竞态条件下,直接累加到该变量上。
  • Cell[]数组:竞态条件下,累加各个线程自己的槽Cell[i]中。

举个形象的例子,火车站买火车票,AtomicLong 只要一个窗口,其他人都在排队;而LongAdder 利用cell开了多个卖票窗口,所以效率高了很多。

LongAdder的基本思路就是分散热点 ,将value值分散到一个Cell数组中,不同线程会命中到数组的不同槽中,各个线程只对自己槽中的那个值进行CAS操作,这样热点就被分散了,冲突的概率就小很多。如果要获取真正的long值,只要将各个槽中的变量值累加返回。

sum()会将所有Cell数组中的value和base累加作为返回值,核心的思想就是将之前AtomicLong一个value的更新压力分散到多个value中去,从而降级更新热点 。

相关文章:

Java——聊聊JUC中的原子变量类

文章目录&#xff1a; 1.什么是原子变量类&#xff1f; 2.AtomicInteger&#xff08;基本类型原子变量类&#xff09; 3.AtomicIntegerArray&#xff08;数组类型原子变量类&#xff09; 4.AtomicMarkableReference&#xff08;引用类型原子变量类&#xff09; 5.AtomicInteger…...

elasticsearch索引与搜索初步

ES支持cURL交互&#xff0c;使用http请求完成索引和搜索操作&#xff0c;最基本的格式如下&#xff1a;创建索引我们可以使用PUT方法创建索引&#xff0c;通过指定“索引”、“类型”、“文档ID”锁定文档&#xff0c;通过参数指定文档的数据。红色部分的路由分别指定了“索引”…...

【Python】多线程与多进程学习笔记

本文是一篇学习笔记&#xff0c;学习内容主要来源于莫凡python的文档&#xff1a;https://mofanpy.com/tutorials/python-basic/threading/thread 多线程 线程基本结构 开启子线程的简单方式如下&#xff1a; import threadingdef thread_job():print(This is a thread of %…...

MySQL基础知识点

1.在Linux上安装好MySQL8.0之后&#xff0c;默认数据目录的具体位置是什么&#xff1f;该目录下都保存哪些数据库组件&#xff1f;在目录/usr/sbin、/usr/bin、/etc、/var/log 分别保存哪些组件&#xff1f; 答&#xff1a;默认数据目录&#xff1a;/var/lib/mysql。保存有mysq…...

代码随想录算法训练营第五十九天| 583. 两个字符串的删除操作、72. 编辑距离

Leetcode - 583dp[i][j]代表以i-1结尾的words1的子串 要变成以j-1结尾的words2的子串所需要的次数。初始化&#xff1a; "" 变成"" 所需0次 dp[0][0] 0, ""变成words2的子串 需要子串的长度的次数,所以dp[0][j] j, 同理&#xff0c;dp[i][0] …...

指针引用字符串问题(详解)

通过指针引用字符串可以更加方便灵活的使用字符串。 字符串的引用方式有两种&#xff0c;下面简单介绍一下这两种方法。 1.用字符数组来存放一个字符串。 1.1 可以通过数组名和下标来引用字符串中的一个字符。 1.2 还可以通过数组名和格式声明符%s输出整个字符串。 具体实…...

数据结构——哈夫曼树编程,输入权值实现流程图代码

一、须知 本代码是在数据结构——哈夫曼树编程上建立的&#xff0c;使用时需将代码剪切到C等软件中。需要输入权值方可实现流程图&#xff0c;但是还需要按照编程换算出的结果自己用笔画出流程图。 下面将代码粘贴到文章中&#xff0c;同时举一个例子&#xff1a;二、代…...

【MySQL】 事务

&#x1f60a;&#x1f60a;作者简介&#x1f60a;&#x1f60a; &#xff1a; 大家好&#xff0c;我是南瓜籽&#xff0c;一个在校大二学生&#xff0c;我将会持续分享Java相关知识。 &#x1f389;&#x1f389;个人主页&#x1f389;&#x1f389; &#xff1a; 南瓜籽的主页…...

Java测试——selenium常见操作(2)

这篇博客继续讲解一些selenium的常见操作 selenium的下载与准备工作请看之前的博客&#xff1a;Java测试——selenium的安装与使用教程 先创建驱动 ChromeDriver driver new ChromeDriver();等待操作 我们上一篇博客讲到&#xff0c;有些时候代码执行过快&#xff0c;页面…...

【三维点云】01-激光雷达原理与应用

文章目录内容概要1 激光雷达原理1.1 什么是激光雷达&#xff1f;1.2 激光雷达原理1.3 激光雷达分类三角法TOF法脉冲间隔测量法幅度调制的相位测量法相干法激光雷达用途2 激光雷达安装、标定与同步2.1 激光雷达安装方式考虑因素2.2 激光雷达点云用途2.3 数据融合多激光雷达数据融…...

自动驾驶感知——物体检测与跟踪算法|4D毫米波雷达

文章目录1. 物体检测与跟踪算法1.1 DBSCAN1.2 卡尔曼滤波2. 毫米波雷达公开数据库的未来发展方向3. 4D毫米波雷达特点及发展趋势3.1 4D毫米波雷达特点3.1.1 FMCW雷达角度分辨率3.1.2 MIMO ( Multiple Input Multiple Output)技术3.2 4D毫米波雷达发展趋势3.2.1 芯片级联3.2.2 专…...

C语言(内联函数(C99)和_Noreturn)

1.内联函数 通常&#xff0c;函数调用都有一定的开销&#xff0c;因为函数的调用过程包含建立调用&#xff0c;传递参数&#xff0c;跳转到函数代码并返回。而使用宏是代码内联&#xff0c;可以避开这样的开销。 内联函数&#xff1a;使用内联diamagnetic代替函数调用。把函数…...

图卷积神经网络(GCN)理解与tensorflow2.0 代码实现 附完整代码

图(Graph),一般用 $G=(V,E)$ 表示,这里的$V$是图中节点的集合,$E$ 为边的集合,节点的个数用$N$表示。在一个图中,有三个比较重要的矩阵: 特征矩阵$X$:维度为 $N\times D$ ,表示图中有 N 个节点,每个节点的特征个数是 D。邻居矩阵$A$:维度为 $N\times N$ ,表示图中 N…...

模电学习6. 常用的三极管放大电路

模电学习6. 常用的三极管放大电路一、判断三极管的工作状态1. 正偏与反偏的概念2. 工作状态的简单判断二、三种重要的放大电路1. 共射电路2. 共集电极放大电路3. 共基极放大电路一、判断三极管的工作状态 1. 正偏与反偏的概念 晶体管分P区和N区&#xff0c; 当P区电压大于N区…...

Lesson 6.6 多分类评估指标的 macro 和 weighted 过程 Lesson 6.7 GridSearchCV 的进阶使用方法

文章目录一、多分类评估指标的 macro 和 weighted 过程1. 多分类 F1-Score 评估指标2. 多分类 ROC-AUC 评估指标二、借助机器学习流构建全域参数搜索空间三、优化评估指标选取1. 高级评估指标的选用方法2. 同时输入多组评估指标四、优化后建模流程在正式讨论关于网格搜索的进阶…...

基于 Python 实时图像获取及处理软件图像获取;图像处理;人脸识别设计 计算机毕设 附完整代码+论文 +报告

界面结果:图像获取;图像处理;人脸识别 程序结构设计 图形用户界面设计与程序结构设计是互为表里的。或者说,程序结构设计是软件设计最本质、最核心的内容。徒有界面而内部逻辑结构混乱的软件一无是处。 Windows 操作系统是一款图形化的操作系统,相比于早期的计算机使用的命…...

前后端RSA互相加解密、加签验签、密钥对生成(Java)

目录一、序言二、关于PKCS#1和PKCS#8格式密钥1、简介2、区别二、关于JSEncrypt三、关于jsrsasign四、前端RSA加解密、加验签示例1、相关依赖2、cryptoUtils工具类封装3、测试用例五、Java后端RSA加解密、加验签1、CryptoUtils工具类封装2、测试用例六、前后端加解密、加验签交互…...

基于Java+SpringBoot+Vue前后端分离学生宿舍管理系统设计与实现

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建、毕业项目实战、项目定制✌ 博主作品&#xff1a;《微服务实战》专栏是本人的实战经验总结&#xff0c;《S…...

前端高频面试题—JavaScript篇(二)

&#x1f4bb;前端高频面试题—JavaScript篇&#xff08;二&#xff09; &#x1f3e0;专栏&#xff1a;前端面试题 &#x1f440;个人主页&#xff1a;繁星学编程&#x1f341; &#x1f9d1;个人简介&#xff1a;一个不断提高自我的平凡人&#x1f680; &#x1f50a;分享方向…...

【微信小游戏开发笔记】第二节:Cocos开发界面常用功能简介

Cocos开发界面常用功能简介 本章只介绍微信小游戏开发时常用的功能&#xff0c;其他功能不常用&#xff0c;写多了记不住&#xff08;其实是懒 -_-!&#xff09;&#xff1a; 层级管理器&#xff0c;用于操作各个节点。资源管理器&#xff0c;用于操作各种文件资源。场景编辑…...

3分钟,学会了一个调试CSS的小妙招

Ⅰ. 作用 用于调试CSS , 比控制台添更加方便&#xff0c;不需要寻找 &#xff1b;边添加样式&#xff0c;边可以查看效果&#xff0c;适合初学者对CSS 的理解和学习&#xff1b; Ⅱ. 快速实现&#xff08;两边&#xff09; ① 显示这个样式眶 给 head 和 style 标签添加一个…...

【项目精选】基于jsp的健身俱乐部会员系统

点击下载源码 社会可行性 随着社会的发展和计算机技术的进步&#xff0c;人类越来越依赖于信息化的管理系统&#xff0c;这种系统能更加方便的获得信息以及处理信息。人们都改变了过去的思维&#xff0c;开始走向了互联网的时代&#xff0c;在 可行性小结 本章在技术可行性上…...

java注解

1. Java注解(Annotation) 2. Java注解分类 3. JDK基本注解 4. JDK元注解 5. 注解分类 6. 自定义注解开发 7. 提取Annotation信息 8. 注解处理器 9. 动态注解处理器(spring aop方式) 1. Java注解(Annotation) Java注解是附加在代码中的一些元信息&#xff0c;用于…...

移动测试相关

一、环境搭建 准备工作&#xff1a; &#xff08;python、pycharm安装配置好&#xff09; 1、Java SDK 安装配置 Java Downloads | Oracle 下载安装后配置系统环境变量&#xff1a;JAVA_HOME&#xff08;jdk根目录路径&#xff09;和path&#xff08;jdk根目录下的bin目录路径…...

SIGIR22:User-controllable Recommendation Against Filter Bubbles

User-controllable Recommendation Against Filter Bubbles 摘要 推荐系统经常面临过滤气泡的问题&#xff1a;过度推荐基于用户特征以及历史交互的同质化项目。过滤气泡将会随着反馈循环增长&#xff0c;缩小了用户兴趣。现有的工作通常通过纳入诸如多样性和公平性等准确性之…...

Python中的进程线程

文章目录前言多进程与多线程基本概念多进程multiprocessing 类对象进程池subprocess模块进程间通信多线程threading实现线程操作线程共享所有变量线程锁参考资料前言 又花了点时间学习了一下Python中的多线程与多进程的知识点&#xff0c;梳理一下供复习参考 多进程与多线程 …...

python(8):使用conda update更新conda后,anaconda所有环境崩溃----问题没有解决,不要轻易更新conda

文章目录0. 教训1. 问题:使用conda update更新conda后&#xff0c;anaconda所有环境崩溃1.1 问题描述1.2 我搜索到的全网最相关的问题----也没有解决3 尝试流程记录3.1 重新安装pip3.2 解决anaconda编译问题----没成功0. 教训 (1) 不要轻易使用conda update更新conda----我遇到…...

c++11 标准模板(STL)(std::multimap)(四)

定义于头文件 <map> template< class Key, class T, class Compare std::less<Key>, class Allocator std::allocator<std::pair<const Key, T> > > class multimap;(1)namespace pmr { template <class Key, class T…...

乐观锁及悲观锁

目录 1.乐观锁 (1).定义 (2).大体流程 (3).实现 (4).总结 2.悲观锁 (1).定义 (2).大体流程 (3).实现 (4).缺点 (5).总结 1.乐观锁 (1).定义 乐观锁在操作数据时非常乐观&#xff0c;认为别的线程不会同时修改数据所以不会上锁&#xff0c;但是在更新的时候会判断一…...

常见的锁策略

注意: 接下来讲解的锁策略不仅仅是局限于 Java . 任何和 "锁" 相关的话题, 都可能会涉及到以下内容. 这些特性主要是给锁的实现者来参考的.普通的程序猿也需要了解一些, 对于合理的使用锁也是有很大帮助的. 1.乐观锁 vs 悲观锁 悲观锁: &#xff08;认为出现锁冲…...

沙井做网站/发外链比较好的平台

一.命令行模式安装图形界面 检查已安装的组   yum grouplist 或者 yum grouplist | more 分页查看安装Gnone   yum groupinstall "GNOME Desktop" 语言设置 localectl status #查看当前语言 locale #查看当前域 localectl list-locales|grep CN #查看当前可用汉…...

app制作网站有哪些 请列举/百度灰色关键词代做

2019独角兽企业重金招聘Python工程师标准>>> 要买新手机了旧手机怎么办&#xff1f;我们可以废物利用下&#xff0c;把旧的手机变成一个远程监控摄像头。这里使用Java创建手机camera客户端和远程服务上的监控界面。 参考原文&#xff1a; Making Android Smart Phon…...

seo是什么职位的缩写/谷歌seo搜索

Sql 四大排名函数&#xff08;ROW_NUMBER、RANK、DENSE_RANK、NTILE&#xff09;简介 排名函数是Sql Server2005新增的功能&#xff0c;下面简单介绍一下他们各自的用法和区别。我们新建一张Order表并添加一些初始数据方便我们查看效果。 CREATE TABLE [dbo].[Order]([ID] [int…...

wordpress日主题官网/腾讯会议付费

...

网站建设用哪种语言好/广告公司的业务范围

有些手机用久了&#xff0c;手机的音量就越来越小&#xff0c;相信很多人都碰到过这种情况&#xff0c;这个时候该怎么办呢&#xff1f;有没有办法来提高手机的音量呢&#xff1f;今天我就来介绍3种方法来提升手机的音量。方法一&#xff1a;开启手机的“单声道音频”。很多手机…...

网站建设一般报价/企业关键词优化最新报价

作者&#xff1a;闲鱼技术-君爱 1. 前言 闲鱼技术团队在2018年引入Flutter后&#xff0c;越来越多的业务场景在Flutter上使用。Flutter的亚秒级热重载一直是开发者的神兵利器&#xff0c;提供给开发者快速修改UI&#xff0c;增加功能&#xff0c;修复bug&#xff0c;不需要重新…...