zoukankan      html  css  js  c++  java
  • 公平的自旋锁

      之前我们了解了自旋锁(见自旋锁浅析),现在来看看怎么让自旋锁变得公平。何谓公平?假如现在有10个线程来抢锁,按顺序排队,0号线程是第一个,9号线程是最后一个,把锁从0号依次传递到9号,这就是公平的。反之,不按先来后到的顺序来,就是不公平的。

      那么怎么实现公平?结合现实生活中的例子,我们去银行或者医院这些地方,首先要做的事情就是取号,然后等待叫号,轮到你了就去窗口办理。后面来的人继续取号,号码累加,而系统按先来后到一个号接一个号处理,只管按自己的号来叫。很明显,这种模式就是公平的,我们的自旋锁可借鉴此种模式来实现:

    package com.wulinfeng.test.testpilling.util;
    
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicInteger;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    
    /**
     * 公平的自旋锁
     *
     * @author wulinfeng
     * @version C10 2018年12月26日
     * @since SDP V300R003C10
     */
    public class FairSpinLock implements Lock
    {
        // 通过AtomicInteger实现CAS,用户排队号,初始0
        private AtomicInteger userNo = new AtomicInteger();
        
        // 通过AtomicInteger实现CAS,系统叫号,初始1
        private AtomicInteger sysNo = new AtomicInteger(1);
        
        // 存储用户排队号,各个线程均可见
        private ThreadLocal<Integer> userNoHolder = new ThreadLocal<Integer>();
        
        @Override
        public void lock()
        {
            // 获取到锁,初始0,自增后此处为1,后续继续自增,把当前的用户号存好,若此时用户号=系统号则获得锁
            Integer currentUserNo = userNo.incrementAndGet();
            
            // 设置到线程副本中
            userNoHolder.set(currentUserNo);
            
            // 无限循环,判断系统叫号与当前用户排队号是否相同
            while (currentUserNo != sysNo.get())
            {
            }
        }
        
        @Override
        public void unlock()
        {
            Integer currentUserNo = userNoHolder.get();
            
            // 释放锁时,把存起来的用户号+1(获取锁时用户号=系统号,所以用户号+1=系统号+1),存到系统号去
            sysNo.compareAndSet(currentUserNo, currentUserNo + 1);
        }
        
        @Override
        public void lockInterruptibly()
            throws InterruptedException
        {
            // TODO Auto-generated method stub
            
        }
        
        @Override
        public boolean tryLock()
        {
            // TODO Auto-generated method stub
            return false;
        }
        
        @Override
        public boolean tryLock(long time, TimeUnit unit)
            throws InterruptedException
        {
            // TODO Auto-generated method stub
            return false;
        }
        
        @Override
        public Condition newCondition()
        {
            // TODO Auto-generated method stub
            return null;
        }
        
    }

      继续用老例子测试:

      @Test
        public void testFairSpinLock()
        {
            // 初始化自旋锁
            FairSpinLock fsl = new FairSpinLock();
            
            for (int i = 0; i < 10; i++)
            {
                new Thread(() -> {
                    {
                        for (int j = 0; j < 10000; j++)
                        {
                            // 加锁
                            fsl.lock();
                            
                            // 自增
                            count++;
                            
                            // 解锁
                            fsl.unlock();
                        }
                        ;
                        
                        // 一个线程执行完了就减1,10个线程执行完了就变成0,执行主线程
                        latch.countDown();
                    }
                }).start();
            }
            
            // 主线程等待
            try
            {
                latch.await();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            
            TestCase.assertEquals(count, 100000);
        }

      输出:

    count值:10000, 耗时:6毫秒.
  • 相关阅读:
    Web基础了解版09-Cookie-Session
    Mysql基础04-查询
    Web基础了解版08-JSTL-Core标签库
    Web基础了解版07-EL表达式-运算符-11个隐式对象
    Web基础了解版06-Jsp-指令、标签-九大隐式对象-四个域对象
    Java语法进阶15-反射及API
    Spark原理概述
    Apache Kafka系列(六)客制化Serializer和Deserializer
    Azkaban时区问题导致调度差1天
    impala jdbc驱动执行impala sql的一个坑(不支持多行sql)
  • 原文地址:https://www.cnblogs.com/wuxun1997/p/10181292.html
Copyright © 2011-2022 走看看