2026/4/13 18:45:24
网站建设
项目流程
单页面网站怎么做的,搜索引擎优化网页,济南哪里有网站公司,wordpress修改用户头像文章目录一、原子类#xff1a;并发世界的秩序维护者二、原子类的四大家族1. 基本类型原子类2. 数组类型原子类3. 引用类型原子类4. 字段更新器三、原子类的核心原理#xff1a;CAS算法CAS的工作原理synchronized vs CAS四、ABA问题及解决方案ABA问题的危害解决方案五、实战案…文章目录一、原子类并发世界的秩序维护者二、原子类的四大家族1. 基本类型原子类2. 数组类型原子类3. 引用类型原子类4. 字段更新器三、原子类的核心原理CAS算法CAS的工作原理synchronized vs CAS四、ABA问题及解决方案ABA问题的危害解决方案五、实战案例构建线程安全的堆栈六、原子类的适用场景与注意事项适用场景注意事项七、总结参考文章大家好我是你们的技术老友科威舟今天给大家分享一下Java并发编程利器Atomic原子类。技术干货满满一文掌握Java原子类的精髓在Java并发编程的世界里多线程安全是一个永恒的话题。想象一下超市排队结账的场景如果收银系统混乱多个顾客同时结账结果会怎样这就像多线程环境下的数据竞争问题。今天我们就来聊聊Java并发包中的排队神器——Atomic原子类。一、原子类并发世界的秩序维护者在并发编程中我们常常遇到这样的问题多个线程同时执行i操作结果可能不如预期。这是因为i看似是一个操作实际上包含读取、增加、写入三个步骤在多线程环境下可能被中断。传统的解决方案是使用synchronized关键字但这就像在超市结账时给整个收银台加锁虽然安全但效率低下。而Atomic原子类则提供了一种更高效的策略它像是一位聪明的收银员能够快速处理每个顾客的请求确保不会混乱。原子类的核心特点是操作不可分割即一个操作要么完全完成要么完全不完成不会出现中间状态。Java的java.util.concurrent.atomic包提供了一系列原子类让我们在不使用锁的情况下实现线程安全。二、原子类的四大家族Atomic原子类可以分为四大类别每种都有其特定的使用场景。1. 基本类型原子类这是最常用的原子类包括AtomicInteger原子更新整型AtomicLong原子更新长整型AtomicBoolean原子更新布尔类型AtomicInteger基本功能使用// 计数器场景AtomicIntegerrequestCountnewAtomicInteger(0);// 每个请求到来时publicvoidhandleRequest(){// 原子性增加不会出现并发问题intcurrentCountrequestCount.incrementAndGet();// 处理请求...}网站访问量统计场景示例// 网站访问量统计场景publicclassWebsiteCounter{privateAtomicIntegerpageViewnewAtomicInteger(0);privateAtomicIntegeruniqueVisitornewAtomicInteger(0);privateAtomicBooleanisWebsiteOnlinenewAtomicBoolean(true);// 页面访问多个线程可能同时调用publicvoidonPageVisit(intvisitorId){// 原子增加访问量intcurrentViewspageView.incrementAndGet();// 使用CAS实现唯一访客统计booleansuccessfalse;while(!success){intcurrentVisitorsuniqueVisitor.get();if(!hasVisitedToday(visitorId)){successuniqueVisitor.compareAndSet(currentVisitors,currentVisitors1);}else{break;}}System.out.println(总访问量: currentViews, 独立访客: uniqueVisitor.get());}// 网站维护切换publicvoidtoggleMaintenanceMode(){booleanoldStatusisWebsiteOnline.getAndSet(!isWebsiteOnline.get());System.out.println(网站状态从 (oldStatus?在线:离线) 切换到 (isWebsiteOnline.get()?在线:离线));}privatebooleanhasVisitedToday(intvisitorId){// 模拟检查逻辑returnfalse;}}2. 数组类型原子类如果你需要原子地更新数组中的元素可以使用AtomicIntegerArray原子更新整型数组的元素AtomicLongArray原子更新长整型数组的元素AtomicReferenceArray原子更新引用类型数组的元素使用示例// 多线程环境下的投票统计AtomicIntegerArrayvoteCountsnewAtomicIntegerArray(10);// 10个候选人// 为候选人投票publicvoidvoteForCandidate(intcandidateId){voteCounts.getAndIncrement(candidateId);}3. 引用类型原子类当需要原子更新对象引用时这些类就非常有用AtomicReference原子更新对象引用AtomicStampedReference带版本号的原子引用解决ABA问题AtomicMarkableReference带标记位的原子引用AtomicReference基本使用示例// 缓存系统中的应用AtomicReferenceCachecacheRefnewAtomicReference();publicvoidupdateCache(CachenewCache){CachecurrentCache;do{currentCachecacheRef.get();// 只有在缓存未被其他线程修改时才会更新}while(!cacheRef.compareAndSet(currentCache,newCache));}用户会话管理使用示例importjava.util.concurrent.atomic.AtomicReference;importjava.util.concurrent.atomic.AtomicStampedReference;// 用户会话管理publicclassUserSessionManager{privateAtomicReferenceUserSessioncurrentSessionnewAtomicReference();// 使用AtomicStampedReference解决ABA问题privateAtomicStampedReferenceBankAccountaccountRefnewAtomicStampedReference(null,0);publicstaticclassUserSession{privateStringuserId;privateStringusername;privatelongloginTime;publicUserSession(StringuserId,Stringusername){this.userIduserId;this.usernameusername;this.loginTimeSystem.currentTimeMillis();}// getters and setters}publicstaticclassBankAccount{privateStringaccountNumber;privatedoublebalance;publicBankAccount(StringaccountNumber,doublebalance){this.accountNumberaccountNumber;this.balancebalance;}// getters and setters}// 原子性的会话切换publicbooleanswitchUserSession(UserSessionnewSession){UserSessionoldSessioncurrentSession.get();System.out.println(尝试从会话 (oldSession!null?oldSession.userId:null) 切换到 newSession.userId);// 使用CAS确保会话切换的原子性booleansuccesscurrentSession.compareAndSet(oldSession,newSession);if(success){System.out.println(会话切换成功);}else{System.out.println(会话切换失败可能已被其他线程修改);}returnsuccess;}// 转账操作避免ABA问题publicbooleantransferMoney(BankAccountfrom,BankAccountto,doubleamount){int[]stampHoldernewint[1];BankAccountcurrentAccountaccountRef.get(stampHolder);intcurrentStampstampHolder[0];// 模拟转账逻辑BankAccountnewFromAccountnewBankAccount(from.getAccountNumber(),from.getBalance()-amount);BankAccountnewToAccountnewBankAccount(to.getAccountNumber(),to.getBalance()amount);// 使用版本戳避免ABA问题returnaccountRef.compareAndSet(from,newFromAccount,currentStamp,currentStamp1);}}4. 字段更新器当你只需要原子更新某个类的字段而不想将整个类包装成原子类时可以使用AtomicIntegerFieldUpdater原子更新对象的int字段AtomicLongFieldUpdater原子更新对象的long字段AtomicReferenceFieldUpdater原子更新对象的引用字段使用示例classUser{publicvolatileintage;// 必须为volatile}// 创建更新器AtomicIntegerFieldUpdaterUserageUpdaterAtomicIntegerFieldUpdater.newUpdater(User.class,age);UserusernewUser();ageUpdater.set(user,30);// 原子性更新age字段三、原子类的核心原理CAS算法Atomic原子类的魔法背后是CASCompare-And-Swap算法它是一种乐观锁策略。CAS的工作原理CAS操作包含三个参数V需要读写的内存位置A预期的原值B想要更新的新值CAS的伪代码实现booleanCAS(V,A,B){if(VA){VB;returntrue;// 操作成功}else{returnfalse;// 操作失败}}当多个线程尝试使用CAS同时更新一个变量时只有其中一个线程能成功其他线程会失败但不会阻塞而是可以再次尝试。synchronized vs CASsynchronized悲观锁假设最坏情况每次操作都会冲突采用独占方式其他线程需要阻塞等待适合竞争激烈、临界区操作复杂的场景CAS乐观锁假设最好情况操作通常不会冲突线程失败后重试不会阻塞适合竞争不激烈、操作简单的场景这就好比两种不同的排队策略synchronized像是一个严格的保安每次只允许一个人进入CAS则像是自助服务大家都可以尝试如果发现冲突就重试。四、ABA问题及解决方案CAS算法虽然高效但存在一个著名的ABA问题如果一个值原来是A变成了B又变回A那么CAS检查时会认为它从来没有被修改过。ABA问题的危害假设一个银行账户系统AtomicIntegeraccountnewAtomicInteger(100);// 线程1尝试扣款50newThread(()-{intcurrentaccount.get();// 模拟一些处理时间Thread.sleep(1000);// 此时账户可能经历了100→50→100的变化booleansuccessaccount.compareAndSet(current,current-50);}).start();// 线程2先扣款再充值newThread(()-{account.addAndGet(-50);// 100 → 50account.addAndGet(50);// 50 → 100}).start();在这个例子中线程1的CAS操作会成功因为它检测到的值确实是100但它不知道中间发生了100→50→100的变化。解决方案AtomicStampedReference通过版本号解决AtomicStampedReferenceIntegeraccountnewAtomicStampedReference(100,0);// 初始值100版本号0// 线程1尝试扣款int[]stampHoldernewint[1];intcurrentaccount.get(stampHolder);intcurrentStampstampHolder[0];// 只有值和版本号都匹配时才更新account.compareAndSet(current,current-50,currentStamp,currentStamp1);AtomicMarkableReference通过标记位解决AtomicMarkableReferenceIntegeraccountnewAtomicMarkableReference(100,false);// 使用标记位来检测变化boolean[]markHoldernewboolean[1];intcurrentaccount.get(markHolder);account.compareAndSet(current,current-50,false,true);// 标记为已修改五、实战案例构建线程安全的堆栈让我们通过一个实际例子来看看AtomicReference的强大之处实现一个线程安全的堆栈。publicclassConcurrentStackT{// 使用原子引用管理栈顶节点privateAtomicReferenceNodeTtopnewAtomicReference();// 入栈操作publicvoidpush(Titem){NodeTnewHeadnewNode(item);NodeToldHead;do{oldHeadtop.get();newHead.nextoldHead;}while(!top.compareAndSet(oldHead,newHead));// CAS直到成功}// 出栈操作publicTpop(){NodeToldHead;NodeTnewHead;do{oldHeadtop.get();if(oldHeadnull){returnnull;// 栈为空}newHeadoldHead.next;}while(!top.compareAndSet(oldHead,newHead));// CAS直到成功returnoldHead.item;}// 节点类privatestaticclassNodeT{publicfinalTitem;publicNodeTnext;publicNode(Titem){this.itemitem;}}}这个实现完全无锁依靠CAS操作保证线程安全在高并发环境下性能优异。六、原子类的适用场景与注意事项适用场景计数器如网站访问量统计状态标志如系统开关控制累积计数如平均值计算对象引用更新如缓存系统注意事项ABA问题在重要业务场景使用带版本号的原子类性能考量高竞争环境下CAS频繁失败可能降低性能单一变量原子类保证单个变量原子性复合操作仍需额外同步可见性保证字段更新器要求字段必须为volatile七、总结Java的Atomic原子类为我们提供了一种高效处理并发的工具。它们基于CAS机制避免了传统锁的开销在适当的场景下能显著提升性能。就像交通管理一样synchronized是红灯——所有车辆必须停止而原子类像是环岛——车辆可以持续行驶只在必要时调整。每种方法都有其适用场景关键在于根据具体需求做出合适选择。希望通过本文你能对Java Atomic原子类有更深入的理解并在实际项目中灵活运用构建出高性能、线程安全的并发系统参考文章https://blog.csdn.net/u014207606/article/details/85107752https://blog.csdn.net/shuiziliu518/article/details/148479334https://bbs.huaweicloud.com/blogs/400010https://blog.51cto.com/u_56701/14054760https://blog.csdn.net/kalman2008/article/details/18606349https://juejin.cn/post/7327724773659394074https://blog.51cto.com/u_16175512/12935133本文主要观点基于以上参考资料结合实际开发经验整理而成。转载请注明出处。*更多技术干货欢迎关注微信公众号科威舟的AI笔记~【转载须知】转载请注明原文出处及作者信息