• Java线程-volatile不能保证原子性


    下面是一共通过volatile实现原子性的例子:

    通过建立100个线程,计算number这个变量最后的结果。

    package com.Sychronized;
    
    public class VolatileDemo {
    
        private volatile int number=0;
        public int getNumber()
        {
            return this.number;
        }
        public void increase()
        {
            this.number++;
        }
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            final VolatileDemo volDemo=new VolatileDemo();
            for(int i=0;i<100;i++)
            {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        volDemo.increase();
                    }
                }).start();
            }
            
            //如果还有子线程在运行,主线程就让出CPU资源
            //直到所有的子线程都运行完了,主线程再继续往下执行
            while(Thread.activeCount()>1)
            {
                Thread.yield();
            }
            
            System.out.println("number:"+volDemo.getNumber());
        }
    
    }

    运行结果:

    发现有几种结果:

    造成这个结果的原因就是,volatile关键字具有可见性,number++实际上有三步操作,但是不具备原子性。

    程序分析:

    number++包含三步操作:1,读取number的值,2,number的值加,3,写入number的值给number变量

    假如当前nubmer=5

    1,线程A读取number的值

    2,线程B读取number的值

    3,线程B执行加1操作

    4,线程B写入最新的number的值。

    此时:主内存:number=6,线程B工作内存:number=6,线程A工作内存:number=5。

    5,线程A执行加1操作

    6,线程A写入最新的number值。

    两次number++操作,只增加了1

    解决方案:

    1,使用synchronized关键字

    2,使用ReentrantLock(java.until.concurrent.locks包下)

    3,使用AtomicInterger(java.util.concurrent.atomic包下)

    可以看这个文章:

    Java并发编程:volatile关键字解析:http://www.importnew.com/18126.html

    第一种:

        private int number=0;
        public int getNumber()
        {
            return this.number;
        }
        public synchronized void increase()
        {
            this.number++;
        }

    或者:

        private int number=0;
        public int getNumber()
        {
            return this.number;
        }
        public  void increase()
        {
            synchronized(this)
            {
                this.number++;
            }
        }

    第二种:

    对执行加锁处理的地方使用 try finally。。操作,在finally里面,执行lock.unlock释放锁

        private int number=0;
        private Lock lock = new ReentrantLock();
        public int getNumber()
        {
            return this.number;
        }
        public  void increase()
        {
            lock.lock();
            try {
                this.number++;
            }finally {
                lock.unlock();
            }
        }

    volatile使用场合

    synchronized关键字是防止多个线程同时执行一段代码,那么就会很影响程序执行效率,而volatile关键字在某些情况下性能要优于synchronized,但是要注意volatile关键字是无法替代synchronized关键字的,因为volatile关键字无法保证操作的原子性。通常来说,使用volatile必须具备以下2个条件:

    1)对变量的写操作不依赖于当前值

    • .不满足:number++,count=count*5等
    • .满足:boolean变量,记录温度变化的变量等

    2)该变量没有包含在具有其他变量的不变式中

    • 不满足:不变式:low<up

    .实际上,这些条件表明,可以被写入 volatile 变量的这些有效值独立于任何程序的状态,包括变量的当前状态。

    事实上,我的理解就是上面的2个条件需要保证操作是原子性操作,才能保证使用volatile关键字的程序在并发时能够正确执行

    volatile使用场景

    (同样摘自文章Java并发编程:volatile关键字解析:http://www.importnew.com/18126.html)

    1.状态标记量

    volatile boolean flag = false;
     
    while(!flag){
        doSomething();
    }
     
    public void setFlag() {
        flag = true;
    }
    volatile boolean inited = false;
    //线程1:
    context = loadContext();  
    inited = true;            
     
    //线程2:
    while(!inited ){
    sleep()
    }
    doSomethingwithconfig(context);

    2.double check

    class Singleton{
        private volatile static Singleton instance = null;
     
        private Singleton() {
     
        }
     
        public static Singleton getInstance() {
            if(instance==null) {
                synchronized (Singleton.class) {
                    if(instance==null)
                        instance = new Singleton();
                }
            }
            return instance;
        }
    }

    synchronized和volatile比较

    • volatile不需要加锁,比synchronized更轻量级,不会阻塞线程;
    • 从内存可见性角度讲,volatile读相当于加锁,volatile写相当于解锁。
    • synchronized既能保证可见性,又能保证原子性,而volatile只能保证可见性,无法保证原子性。
  • 相关阅读:
    【Selenium WebDriver】浏览器操作篇:打开浏览器、打开URL、关闭浏览器、获取页面的URL, Title, Source
    【读书笔记----云计算】云计算前世今生(基本概念)
    【Servlet入门】HelloServlet 小例子
    【Web前端知识从零开始】-- 浏览器F12、DOM 基础、页面元素定位
    生活常识
    工具的使用技巧
    业务知识
    工作方式
    Oracle SQL
    出差-闽西
  • 原文地址:https://www.cnblogs.com/alsf/p/8321254.html
Copyright © 2020-2023  润新知