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

Java:从单线程计数器到多线程数据同步synchronized和原子类Atomic

目录

    • 使用单线程
    • 使用多线程
    • 使用多线程 + synchronized
    • 使用多线程 + 原子类AtomicLong

使用单线程

单线程修改计数器的值,没有发生问题,每次运行结果都是10000,不过程序耗时较长

package com.example;/*** 计数器*/
class Counter {private static long count;public static long getCount() {return count;}public static void incrementCount() {count++;}
}public class Demo {public static void main(String[] args) throws InterruptedException {long count = Counter.getCount();System.out.println(count);// 0for (int i = 0; i < 10000; i++) {try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}Counter.incrementCount();}count = Counter.getCount();System.out.println(count);// 10000}
}

使用多线程

单线程修改计数器的值,运行速度提高了,不过运行结果每次都不一致,而且结果不是10000

package com.example;import java.util.ArrayList;
import java.util.List;/*** 计数器*/
class Counter {private static long count;public static long getCount() {return count;}public static void incrementCount() {count++;}
}public class Demo {public static void main(String[] args) throws InterruptedException {long count = Counter.getCount();System.out.println(count);// 0List<Thread> list = new ArrayList<>();// 启动10000个线程同时访问计数器for (int i = 0; i < 10000; i++) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}Counter.incrementCount();}});list.add(thread);}for (Thread thread : list) {thread.start();}for (Thread thread : list) {thread.join();}count = Counter.getCount();System.out.println(count);}
}

执行结果

第一次:9910
第二次:9912
第三次:9910

使用多线程 + synchronized

多线程加锁后,最后结果都是10000

package com.example;import java.util.ArrayList;
import java.util.List;/*** 计数器*/
class Counter {private static long count;public static long getCount() {return count;}public static synchronized void incrementCount() {count++;}
}public class Demo {public static void main(String[] args) throws InterruptedException {long count = Counter.getCount();System.out.println(count);// 0List<Thread> list = new ArrayList<>();// 启动10000个线程同时访问计数器for (int i = 0; i < 10000; i++) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}Counter.incrementCount();}});list.add(thread);}for (Thread thread : list) {thread.start();}for (Thread thread : list) {thread.join();}count = Counter.getCount();System.out.println(count);}
}

执行结果

第一次:10000
第二次:10000
第三次:10000

使用多线程 + 原子类AtomicLong

多线程中使用原子类AtomicLong实现计数器,最后结果都是10000

原理是CAS(Compare and Set):

  • 先比较原始值和预期值,如果相等,则修改为新值;
  • 不相等则修改失败

伪代码如下

bool compareAndSet(oldValue, expectValue, updateValue){if(oldValue == expectValue){oldValue = updateValue// update success} else{// update fail}
}
package com.example;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;/*** 计数器*/
class Counter {private static AtomicLong count = new AtomicLong(0);public static long getCount() {return count.get();}public static void incrementCount() {count.incrementAndGet();}
}public class Demo {public static void main(String[] args) throws InterruptedException {long count = Counter.getCount();System.out.println(count);// 0List<Thread> list = new ArrayList<>();// 启动10000个线程同时访问计数器for (int i = 0; i < 10000; i++) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}Counter.incrementCount();}});list.add(thread);}for (Thread thread : list) {thread.start();}for (Thread thread : list) {thread.join();}count = Counter.getCount();System.out.println(count);}
}

执行结果

第一次:10000
第二次:10000
第三次:10000

参考

  1. 使用Atomic-廖雪峰的官方网站
  2. CAS锁机制(无锁、自旋锁、乐观锁、轻量级锁)
  3. java中的Atomic类

相关文章:

Java:从单线程计数器到多线程数据同步synchronized和原子类Atomic

目录 使用单线程使用多线程使用多线程 synchronized使用多线程 原子类AtomicLong 使用单线程 单线程修改计数器的值&#xff0c;没有发生问题&#xff0c;每次运行结果都是10000&#xff0c;不过程序耗时较长 package com.example;/*** 计数器*/ class Counter {private st…...

提前进入行业顶尖阵营:高性能计算实习的竞争优势

如今就业越来越内卷&#xff0c;尤其是计算机行业更是如此。加上GPT以及大模型的加持&#xff0c;各大企业纷纷降本增效&#xff0c;普通程序员逐渐失去竞争力。想要在竞争激烈的就业市场中脱颖而出&#xff0c;提前进入行业顶尖阵营是一个明智的选择。而高性能计算实习将为您提…...

Java程序设计入门教程--标识符和关键字

目录 标识符 标识符的约定 标识符 1. 定义 用来标识类名&#xff0c;变量名&#xff0c;方法名&#xff0c;类型名&#xff0c;数组名&#xff0c;文件名的有效序列称为标识符。简单地说&#xff0c;标识符就是一个名字。 2. 标识符命名规则 &#xff08;1&#xff09;大小…...

国产IC芯片自动化测试系统ATECLOUD,助力芯片测试自动化

IC芯片测试成本是影响制造和加工成本的重要因素。在某些情况下&#xff0c;测试成本可能占到器件总成本的40%左右。为了降低测试成本&#xff0c;可以优化测试程序并研发多工位测试。同时&#xff0c;必须平衡良品率和测试时间&#xff0c;以实现最佳的成本控制。本篇文章纳米软…...

BeanFactory和ApplicationContext有什么区别?

BeanFactory和ApplicationContext有什么区别&#xff1f; BeanFactory和ApplicationContext有什么区别&#xff1f; BeanFactory和ApplicationContext有什么区别&#xff1f; BeanFactory (轻量级) 和ApplicationContext(高级特性和框架)是Spring的两大核心接口&#xff0c;都…...

js的BOM对象中的window、location使用

说明&#xff1a;BOM的全称是Browser Object Model&#xff0c;浏览器对象模型&#xff0c;有Window&#xff08;浏览器窗口&#xff09;、Navigator&#xff08;浏览器&#xff09;、Screen&#xff08;屏幕&#xff09;、History&#xff08;历史记录&#xff09;和Location&…...

DAY 68 redis高可用的主从复制、哨兵、cluster集群

Redis 高可用 什么是高可用 在web服务器中&#xff0c;高可用是指服务器可以正常访问的时间&#xff0c;衡量的标准是在多长时间内可以提供正常服务(99.9%、99.99%、99.999%等等)。 但是在Redis语境中&#xff0c;高可用的含义似乎要宽泛一些&#xff0c;除了保证提供正常服…...

leetcode 1209 学会删除字符串

删除字符串的经典kotlin操作&#xff1a; val mTemp (temp.text).replace(Regex("℃"),"") 以下是题目&#xff01; 1209. 删除字符串中的所有相邻重复项 II 提示 中等 174 相关企业 给你一个字符串 s&#xff0c;「k 倍重复项删除操作」将会从 s…...

JavaScript6

一、概念 ES6是JavaScript语言的标准。 新特性&#xff1a;let和const命令、变量的解构赋值、字符串函数对象数组等扩展。 环境准备&#xff1a;需要安装NodeJs。 二、新特性 1、let let命令用来声明变量。他的用法类似var&#xff0c;但所声明的变量&#xff0c;只在let命令…...

轻松安装Redis:不用担心配置问题

一、Centos安装Redis 1.安装 EPEL 源 Redis 不在 CentOS 官方仓库中&#xff0c;需要安装 EPEL 源才能访问到 Redis 软件包。运行以下命令安装 EPEL 源&#xff1a; sudo yum install epel-release 2.安装 Redis 使用以下命令安装 Redis&#xff1a; sudo yum install re…...

ChatGPT学习研究总结

目录 ChatGPT研究总结 一、程序接入用途不大 二、思考&#xff1a;如何构建一个类似ChatGPT的自定义模型 一些ChatGPT研究学习资料&#xff08;来源网络&#xff09; &#xff08;1&#xff09;一文读懂ChatGPT模型原理 &#xff08;2&#xff09;MATLAB科研图像处理——…...

SpringBoot枚举入参实战

文章目录 前言一、什么是枚举&#xff1f;二、枚举的优点三、枚举的缺点四、使用步骤1.代码实现1.1.枚举1.2.实体1.3.控制层 2.Postman测试2.1.Get请求2.1.1.枚举参数2.1.2.对象枚举属性参数 2.2.Post请求2.2.1.枚举参数2.2.2.对象枚举属性参数 2.3.Put请求2.3.1.枚举参数2.3.2…...

Ansible介绍

文章目录 Ansible介绍Ansible的架构为什么要有Ansible TowerAnsible Tower Ansible介绍 Ansible是一种自动化工具&#xff0c;可以用于自动化部署、配置和管理IT基础设施。它是一种基于Python的开源软件&#xff0c;提供了一个简单易用的语言和工具集&#xff0c;使得自动化管…...

GPT-4的免费使用方法分享

目录 方法1&#xff1a;使用Ora.sh的LLM应用 方法2&#xff1a;使用https://steamship.com 方法3&#xff1a;使用https://nat.dev 方法4&#xff1a;http://tdchat.vip 方法5&#xff1a;使用Poe网站或App 方法6&#xff1a;使用 Opencat App 方法7:使用https://Huggin…...

一个产品的诞生

一个产品的诞生 一个产品的诞生通常需要经历多个阶段&#xff0c;包括市场调研、产品设计、原型制作、测试和生产等。在市场调研阶段&#xff0c;公司会了解消费者的需求和市场趋势&#xff0c;以确定产品的定位和特点。在产品设计阶段&#xff0c;设计师会根据市场调研结果和…...

MQTT与传统的HTTP协议对比,优势在哪里呢?

HTTP是应用最为广泛和流行的协议。但是MQTT在过去的几年里迅速取得了进展。在讨论物联网开发的时候&#xff0c;开发者必须在这两者之间作出选择。 MQTT集中于数据&#xff0c;而HTTP集中于文档。HTTP是一个用于客户端-服务器计算的请求-响应协议&#xff0c;它并非总是为移动设…...

热榜!阿里出品2023版Java架构师面试指南,涵盖Java所有核心技能

最近很多粉丝朋友私信我说&#xff1a;熬过了去年的寒冬却没熬过现在的内卷&#xff1b;打开Boss直拒一排已读不回&#xff0c;回的基本都是外包&#xff0c;薪资还给的不高&#xff0c;对技术水平要求也远超从前&#xff1b;感觉Java一个初中级岗位有上千人同时竞争&#xff0…...

【小程序】封装时间选择组件:用单元格van-cell和插槽slot,包括起始时间和终止时间

效果 可以选择起始时间和终止时间&#xff0c;并显示。 时间选择器放在van-cell的value插槽中。 用的库&#xff1a; https://vant-contrib.gitee.io/vant-weapp/#/home https://dayjs.fenxianglu.cn/category/ 用的组件&#xff1a;Cell单元格、DatetimePicker时间选择、Pop…...

华为OD机试真题B卷 Java 实现【猜密码】

一、题目描述 小杨申请了一个保密柜,但是他忘记了密码。只记得密码都是数字,而且所有数字都是不重复的。 请你根据他记住的数字范围和密码的最小数字数量,帮他算下有哪些可能的组合,规则如下: 输出的组合都是从可选的数字范围中选取的,且不能重复;输出的密码数字要按照…...

沉淀-MYSQL

MYSQL学习 数据库操作 创建数据库 create database db_name; 删除数据库 drop database db_name; 选择/使用数据库 use db_name; 使用mysqladmin在终端执行 创建数据库 mysqladmin -u root -p create db_name Enter password:*** 删除数据库 mysqladmin -u root -p drop db…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...