• JUC--volatiley&CAS


    public class VolatileTest {
        public static void main(String[] args) {
            ThreadDemo td = new ThreadDemo();
            new Thread(td).start();
            while(true){
                if(td.getFlag()){
                    System.out.println("========");
                    break;
                }
            }
    
        }
    }
    class ThreadDemo implements Runnable{
       private boolean flag=false;
    
        @Override
        public void run() {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            flag=true;
            System.out.println("flag="+getFlag());
    
        }
        public boolean getFlag(){
            return flag;
        }
    }

    flag是main thread和td共享的数据,他们都在各自的线程内有一个copy,由于while true的速度十分快,main thread不能读取到td修改后的值,所以只能输出 flag=true。

    内存不可见性:当多个thread操作共享数据时,彼此不可见

    volatile:当多个thread操作共享数据时,保证数据是可见的,内存栅栏   可以理解为多个线程直接操作主存中的数据

    因为使用vloatile 不能指令重排  所以效率低

    volatile相比synchronized:

      是一种较为轻量级的同步策略,volatile不具备互斥性,两个线程可以同时访问共享数据,volatile不能保证变量的原子性,

    原子性问题:i++

      

    以下情况使用volatile不能解决非原子性问题:内存可见性问题依然存在

    public class AtomicTest {
        public static void main(String[] args) {
            AtomicDemo ad = new AtomicDemo();
            for(int i=0;i<10;i++){
                new Thread(ad).start();
            }
        }
    }
    class AtomicDemo implements Runnable{
        private int serialNum=0;
        @Override
        public void run() {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+":"+getSerialNum());
        }
        public int getSerialNum(){
            return serialNum++;
        }
    }

    二、使用源自变量 java.util.concurrent.atomic 原子变量包

      1.使用volatile保证内存可见性

      2.使用CAS compare and swap算法保证数据的原子性

        CAS是硬件对于并发操作共享数据的支持  

        CAS包含三个操作数:

          内存值V 预估值A 更新值B

    (1)首先读取内存之V 在替换的时候读取旧值A 

    AtomicInteger:保证线程安全  内存可见性 原子性问题

    private AtomicInteger serialNum=new AtomicInteger();
        @Override
        public void run() {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+":"+getSerialNum());
        }
        public int getSerialNum(){
            return serialNum.getAndIncrement();
        }

     CAS算法的模拟:

    public class TestCAS {
        public static void main(String[] args) {
            final CompareAndSwap cas = new CompareAndSwap();
    
            for(int i=0;i<10;i++){
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        int expectVal = cas.get();
                        boolean b= cas.compareAndSwap(expectVal,(int)(Math.random()*101));
                    }
                }).start();
            }
        }
    }
    
    class CompareAndSwap {
        private int value;
        public synchronized int get() {
            return value;
        }
        public synchronized int cas(int expectVal, int newVal) {
            int oldVal = value;
            if (oldVal == expectVal)
                this.value = newVal;
            return oldVal;
        }
        public synchronized boolean compareAndSwap(int expectVal, int newVal) {
            return  expectVal==cas(expectVal,newVal);
        }
    }
  • 相关阅读:
    Delphi中Android运行和JNI交互分析
    C++ 中内存分配和回收
    Delphi Android程序启动过程
    Delphi XE的RTTI增强,动态Hook某些内部事件
    Win7下超级管理员创建普通权限任务
    再探Delphi2010 Class的构造和析构顺序
    Delphi2010新发现-类的构造和析构函数功能
    【背包专题】01背包
    Delphi2010的RTTI增强
    用WebBrowser实现HTML界面的应用和交互 good
  • 原文地址:https://www.cnblogs.com/zhy-study/p/9398751.html
Copyright © 2020-2023  润新知