volatile使用例子 原子性使用例子

发布时间:2026/11/5 18:10:20
volatile使用例子 原子性使用例子 1. 内存可见性问题: ??现象主存中数据改了但是Main线程中获取的数据没有跟新package com.denganzhi.pp; public class Main { public static void main(String[] args) { ThreadDemo threadDemonew ThreadDemo(); new Thread(threadDemo).start(); while(true){ // synchronized(threadDemo){ if(threadDemo.isFlag()){ System.out.println(--main---); break; } // } } } } class ThreadDemo implements Runnable{ //private volatile boolean flagfalse; private boolean flagfalse; Override public void run() { try { Thread.sleep(200); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } flagtrue; System.out.println(ThreadDemo-flag:flag); } public boolean isFlag() { return flag; } }执行结果 Main 线程 while 循环中获取的 是 false问题原因private boolean flagfalse;是多个线程共享数据,存在主存中,堆内存中Java 每一个线程运行在栈中线程1 获取flag 读到自己的栈中改掉flagtrue,然后在写到主存中去Main线程 上来读取 主存数据 flagfalse,Main线程 后面 while(true) 该代码系统底层执行效率非常高不会进行系统调用永远取的是 Main线程中数据, 返回的是false解决方法1synchronized(threadDemo)保证Main线程每次执行的时候,都到主存中更新一下但是synchronized效率低如果一个线程持有锁另外一个线程阻塞等待cpu调度package com.denganzhi.pp; public class Main { public static void main(String[] args) { ThreadDemo threadDemonew ThreadDemo(); new Thread(threadDemo).start(); while(true){ synchronized(threadDemo){ if(threadDemo.isFlag()){ System.out.println(--main---); break; } } } } } class ThreadDemo implements Runnable{ //private volatile boolean flagfalse; private boolean flagfalse; Override public void run() { try { Thread.sleep(200); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } flagtrue; System.out.println(ThreadDemo-flag:flag); } public boolean isFlag() { return flag; } }运行结果 Main线程获取true解决效率低问题直接操作主存中数据,使用volatile 关键字解决问题package com.denganzhi.pp; public class Main { public static void main(String[] args) { ThreadDemo threadDemonew ThreadDemo(); new Thread(threadDemo).start(); while(true){ // synchronized(threadDemo){ if(threadDemo.isFlag()){ System.out.println(--main---); break; } // } } } } class ThreadDemo implements Runnable{ private volatile boolean flagfalse; Override public void run() { try { Thread.sleep(200); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } flagtrue; System.out.println(ThreadDemo-flag:flag); } public boolean isFlag() { return flag; } }输出结果Main线程获取truevolatile问题1. volatile 不具备 互斥性2. volatile 不能保证 变量的 原子性2. 什么是原子性int i0;iint temp i ; // i存储主存中, 线程A读存入tempii1; // 线程A执行i temp; // 线程A把 值 写入主存中上面是3个操作不可以分隔, 叫做原子性但是 在线程A 读取的时候线程 B也读取了,A 写入数据的时候 写入以后主存数据变1B 也写入 写入以后主存储数据变1破坏原子性这个时候会有2个重复数据 比如下列代码package com.denganzhi.pp; public class Main2 { public static void main(String[] args) { AtomicDemo auAtomicDemonew AtomicDemo(); for (int i 0; i 10; i) { new Thread(auAtomicDemo).start(); } } } class AtomicDemo implements Runnable{ private int serialNumber0; Override public void run() { // TODO Auto-generated method stub try { Thread.sleep(200); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getId() name: getSerialNumber()); } public int getSerialNumber() { return serialNumber; } }执行 结果出现重复数据原子性被破坏CAS算法 JVM 底层 对CAS算法 进行了支持解决上面问题但是没有解决原子性问题多次线程可以同时执行,只有其中一个 线程 可以执行成功但是不会阻塞线程原理内存值 V预估值 A更新值 B当且 当 VA 时, VB ,否则不做任何操作例子线程A读1 V0snsn1读2 A0在写入之前读取VAB1 写入 主存中线程B读1 V0snsn1读2 A1 V ! A写入失败线程C....失败线程D... 失败失败了但是没有阻塞CPU还可以继续调度,就是由于这个原因优于 synchronized使用 CAS 算法解决上面问题* jdk1.5 原子性提供api接口*java.util.concurrent.atomic 下提供 类 实现了CAS 算法来解决原子性并没有解决原子性(要解决只能使用sychronized)AtomicBooleanAtomicInteger: Int类型AtomicIntegerArray 数组AtomicIntegerFieldUpdaterAtomicLongAtomicLongArrayAtomicLongFieldUpdaterAtomicMarkableReferenceAtomicReferenceAtomicReferenceArrayAtomicReferenceFieldUpdaterAtomicStampedReference代码实现public class Main2 { // 实现抢票 用例 public static void main(String[] args) { AtomicDemo auAtomicDemonew AtomicDemo(); Thread threadnull; for (int i 0; i 7; i) { threadnew Thread(auAtomicDemo); thread.setName(线程:i ); thread.start(); } } } class AtomicDemo implements Runnable{ // 还 剩下 5 张票 7个人来 抢票 AtomicInteger automicIntegernew AtomicInteger(5); Override public void run() { // TODO Auto-generated method stub try { Thread.sleep(200); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } int numgetSerialNumber(); if(num 0){ System.err.println(Thread.currentThread().getName() 没有抢到火车票); }else{ System.out.println(Thread.currentThread().getName() 抢到第 num 张火车票); } } public int getSerialNumber() { return automicInteger.getAndDecrement(); //-- } }线程:4 抢到第2张火车票线程:3 抢到第1张火车票线程:0 没有抢到火车票线程:1 抢到第5张火车票线程:6 抢到第3张火车票线程:2 抢到第4张火车票线程:5 没有抢到火车票

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询