zoukankan      html  css  js  c++  java
  • Java并发程序设计(七)乐天派:无锁

    无锁

    一、概述

    无锁是处理并发的一种乐观策略,它会假设对资源的访问是没有冲突的。既然没有冲突自然不需要等待,所以所有的线程都可以在不停顿的状态下执行。那遇到冲突怎么办?接下来请看,无锁绝招“CAS”即比较交换术。

    二、CAS原理

    CAS即Compare and swap.其算法过程是这样的:它有三个参数:

    1.V表示要更新的变量

    2.E表示期望值

    3.N表示新值

    仅当V等于E时,才会将V设为N。如果V和N不同,则说明有其他线程做了更新,则该线程什么都不做。当多个线程同时使用CAS进行变量操作时,只有一个会更新成功,其余都会失败。失败的线程不会被挂起,而是进行重试。

    三、无锁的线程安全整数:AtomicInteger

    AtomicInteger主要方法如下(对于其他无锁线程安全类,其方法类似):

    public final int get() //取得当前值
    public final void set(int newValue) //设置当前值
    public final int getAndset(int newValue) //设置新值返回旧值
    public final boolean compareAndSet(int except,int u) //如果当前值为except则设为u
    public final int getAndIncrement() //当前值加1返回旧值
    public final int getAndDecrement() 
    public final int getAndAdd(int delta)
    public final int incrementAndGet()
    public final int decrementAndGet()
    public final int addAndGet() 

    就AtomicInteger核心字段:

    private volatile int value; //代表AtomicInteger当前的值
    private static final long valueOffset; //value字段的偏移量

    AtomicInteger的使用示例:

    public class AutomicIntegerDemo {
    
        static AtomicInteger i=new AtomicInteger();
    
        public static class addThread implements Runnable{
    
            @Override
            public void run() {
                for(int j=0;j<1000;j++){
                    i.incrementAndGet();
                }
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            Thread[] ts=new Thread[10];
            for(int j=0;j<10;j++){
                ts[j]=new Thread(new addThread());
            }
    
            for(int j=0;j<10;j++) ts[j].start();
            for (int j=0;j<10;j++) ts[j].join();
    
            System.out.println(i);
        }
    }

    相比使用锁,使用无锁会有更好的性能。

    四、CAS算法逻辑上瑕疵及解决办法:AtomicStampedReference

    CAS算法逻辑上的瑕疵:当你获得对象当前数据后,在准备修改为新值前,对象的值被其他对象连续修改了两次,而经过这两次修改后,对象的值又恢复到旧值。这样,当前线程就无法判断该值是否被修改过。也就是说你修改的对象数值没有过程状态信息。

    AtomicStampedReference内部不仅维护了对象值还维护了一个状态值。

    五、无锁数组

    当前可用的原子数组有:AtomicIntegerArray,AtomicLongArray和AtomicReferenceArray

    public class AtomicIntegerArrayDemo {
    
        static AtomicIntegerArray array=new AtomicIntegerArray(10);
    
        public static class addThread implements Runnable{
    
            @Override
            public void run() {
                for (int j=0;j<1000;j++){
                    array.getAndIncrement(j%array.length());
                }
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            Thread[] ts=new Thread[10];
            for (int j=0;j<10;j++){
                ts[j]=new Thread(new addThread());
            }
    
            for (int j=0;j<10;j++) ts[j].start();
    
            for (int j=0;j<10;j++) ts[j].join();
    
            System.out.println(array);
        }
    }

    六、让普通变量也享受原子操作:AtomicIntegerFieldUpdater

    public class AtomicIntegerFieldUpdaterDemon {
    
        public static class Candidate{
            int id;
            volatile int score;
        }
    
        public final static AtomicIntegerFieldUpdater<Candidate> scoreUpdater=
                AtomicIntegerFieldUpdater.newUpdater(Candidate.class,"score");
    
        public static AtomicInteger checkScore=new AtomicInteger(0); //用于检测
    
        public static void main(String[] args) throws InterruptedException {
            final Candidate candidate=new Candidate();
            Thread[] threads=new Thread[1000];
            for (int i=0;i<1000;i++){
                threads[i]=new Thread(){
                    public void run(){
                        if (Math.random()>0.4){
                            scoreUpdater.incrementAndGet(candidate);
                            checkScore.incrementAndGet();
                        }
                    }
                };
                threads[i].start();
            }
    
            for (int i=0;i<1000;i++) threads[i].join();
            System.out.println("score="+candidate.score);
            System.out.println("checkScore="+checkScore);
        }
    }

    注意事项:

    1.Updater只能修改可见范围内的变量。

    2.变量必须是volatile

    3.变量不能是static的

    Simple is important!
  • 相关阅读:
    希望走过的路成为未来的基石
    第三次个人作业--用例图设计
    第二次结对作业
    第一次结对作业
    第二次个人编程作业
    第一次个人编程作业(更新至2020.02.07)
    Springboot vue 前后分离 跨域 Activiti6 工作流 集成代码生成器 shiro权限
    springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离
    spring cloud springboot 框架源码 activiti工作流 前后分离 集成代码生成器
    java代码生成器 快速开发平台 二次开发 外包项目利器 springmvc SSM后台框架源码
  • 原文地址:https://www.cnblogs.com/Shadowplay/p/7484474.html
Copyright © 2011-2022 走看看