zoukankan      html  css  js  c++  java
  • JUC 并发编程--12, 使用AtomicInteger 实现一把锁(排队自旋锁), 代码演示

    前面 使用自旋锁实现了一把锁,(请看 第5篇)

    volatile 三大特性: 可见性, 不保证原子性, 禁止指令重排
    为了解决 volatile不保证原子性的问题, 引入了原子类, AtomicInteger, 底层是使用了 CAS 直接变成汇编指令操作硬件,从而解决了 原子性的问题
    而 Lock 类的底层实现是 AQS 和CAS,
    这里使用 AtomicInteger的特性和自旋锁来实现一把 排队自旋锁 锁:

      class AtomicLock {
        private AtomicInteger serviceNum = new AtomicInteger();//等待者
        private AtomicInteger ticketNum = new AtomicInteger();//排队号
    
        public int atomicLock() {
            // 排队号加1
            int myTicketNum = ticketNum.getAndIncrement();
            //只要 排队号和 等待着的号不同,等待者就一直循环,  如果相同,就返回排队号,  这里相当于加锁成功
            while (serviceNum.get() != myTicketNum) {
            }
            System.out.println(Thread.currentThread().getName() + "加锁成功");
            return myTicketNum;
        }
    
        public void atomicUnlock(int num) {
            // 如果要解锁,就将排队号 +1, 并设置回等待者
            int next = num + 1;
            serviceNum.compareAndSet(num, next);
            System.out.println(Thread.currentThread().getName() + "解锁成功");
        }
    
        static int num = 0;
        public static void main(String[] args) throws InterruptedException {
            /**
             * 这个锁的缺点是: 如果线程很多, 这么多线程都要操作 同一个Atomicinteger,  且为了保证 各个线程的工作缓存中的数据一致性,
             * 会频繁的 在工作缓存和 主存之间进行通信,,造成系统总线和主存之间繁重的流量, 进而降低系统的性能
             *
             * 但是多处理器系统上,每个进程/线程占用的处理器都在读写同一个变量serviceNum ,每次读写操作都必须在多个处理器缓存之间进行缓存同步,
             * 这会导致繁重的系统总线和内存的流量,大大降低系统整体的性能。
             * 如何解决:  使用  CLH锁和MCS锁
             */
            AtomicLock atomicLock = new AtomicLock();
            for (int i = 0; i < 10; i++) {
                new Thread(() -> {
                    int j = atomicLock.atomicLock();
                    System.out.println(Thread.currentThread().getName() + "操作开始: num: " + num);
                    for (int k = 0; k < 20; k++) {
                        num++;
                    }
                    System.out.println(Thread.currentThread().getName() + "操作结束: num: " + num);
                    atomicLock.atomicUnlock(j);
                },"线程"+i).start();
            }
    
            TimeUnit.SECONDS.sleep(3);
            System.out.println("最终结果num: "+num);
        }
    }
    

    运行结果:

    CLH锁和 MCS锁, 这个是目前写的比较好的博客
    https://www.jianshu.com/p/1b1b44e84394

  • 相关阅读:
    C#随机数字生成的一种方法
    SqlServer2012自增主键跳跃增长的问题解决方案
    Mysql5.7初始化成空密码或随机密码的方式
    StyleCop的常见错误
    数据库同步相关的SQL语句
    Linux Shell角本中的条件判断
    Linux(CentOS)中使用Mono+jexus部署Asp.net4.5网站
    Mina.Net实现的UDP多路广播
    Linux CentOS 6.6安装JDK1.7
    linux 常用命令
  • 原文地址:https://www.cnblogs.com/lvcai/p/13704633.html
Copyright © 2011-2022 走看看