根据CAS自定义设计秒杀系统 java开的后门应用二

1 前提

因为看了AtomicInteger 发现他的锁的实现基于CAS,那同样的道理,我们也可以设计一个秒杀系统

1.1 当秒杀来临时 定义线程池去处理

    ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 100,
            60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1000), new RejectedExecutionHandler()    {
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            //定义线程池的拒绝策略 直接丢弃
            log.info("discard:{}",r);
        }
    });

1.2 模拟高并发 一秒1百万并发

    public void testCas(){
        CyclicBarrier barrier = new CyclicBarrier(100);
        List list=new ArrayList();
        IntStream.range(0,1000000).forEach(list::add);
        list.parallelStream().forEach(o->{
            int finalI = o;
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    User user=new User();
                    user.setUserId(finalI);
                    casService.testCasMulti(user);

                }
            });
        });
    }

关键代码 1.3

    // Unsafe mechanics java 留给
    private static final sun.misc.Unsafe U;

    private static final long INIT_CONTROL;
    //静态代码块
    static {
        try {
//            U = sun.misc.Unsafe.getUnsafe();
            //初始化 通过反射
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            //获取unsafe 
            U = (Unsafe) f.get(null);
            Class k = CasServiceImpl.class;
            //将 initControl的值初始化给INIT_CONTROL  完成后面的compareAndSwapInt()操作
            INIT_CONTROL = U.objectFieldOffset
                    (k.getDeclaredField("initControl"));
        } catch (Exception e) {
            throw new Error(e);
        }
    }

1.4以下是业务代码

public void testCasMulti(User user) {
        BigDecimal One = new BigDecimal(1);
        while (true) {
            //先检查库存有木有 如果没有就进行下面的操作
            Integer param = (Integer) redisUtil.get("kucun");
            if(param<=0){
                //log.info("停止循环");
                break;
            }
            int initControlLocal = initControl;
            /**
             * 如果已经有线程在进行获取了,则直接放弃cpu
             */
            if (initControlLocal < 0) {
//                log.info("initControlLocal < 0,just yield and wait");
                /**
                 * 这里可以不要这个,可以睡眠一小会。
                 */
//                Thread.yield();
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    log.warn("e:{}", e);
                }
                continue;
            }


            /**
             * 争夺控制权
             */
            boolean bGotChanceToInit = U.compareAndSwapInt(this,
                    INIT_CONTROL, initControlLocal, -1);
            if (bGotChanceToInit) {
                try {
                    log.info("用户user={},获取到竞争锁",user.getUserId());
                    //扣减库存
                    redisUtil.decr("kucun",1L);
                } finally {
                    initControl = 0;
                }

                break;
            }
        }
    }

    private volatile int initControl;

看下运行结果


image.png
image.png

1.5运行过程

1)当大量请求过来时,首先由线程池执行任务,线程池不断的把任务分配给线程,corepoolsize不足,就把任务缓存到队列,队列已经满了,就继续开线程,直接到最大值max时,就丢弃任务。
2)线程池执行的任务调用业务层,发现有一些线程先抢占了任务,其他线程睡眠,或者自旋等待
3)获取锁的线程执行扣减库存的任务

【源码地址】https://github.com/pw09066310/my.git

参考链接

【1】https://www.cnblogs.com/grey-wolf/p/13093378.html

你可能感兴趣的:(根据CAS自定义设计秒杀系统 java开的后门应用二)