ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

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

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 没有抢到火车票
返回列表