根據(jù)CAS自定義設(shè)計(jì)秒殺系統(tǒng) java開的后門應(yīng)用二

1 前提

因?yàn)榭戳薃tomicInteger 發(fā)現(xiàn)他的鎖的實(shí)現(xiàn)基于CAS,那同樣的道理,我們也可以設(shè)計(jì)一個秒殺系統(tǒng)

1.1 當(dāng)秒殺來臨時 定義線程池去處理

    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 模擬高并發(fā) 一秒1百萬并發(fā)

    public void testCas(){
        CyclicBarrier barrier = new CyclicBarrier(100);
        List<Integer> 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);

                }
            });
        });
    }

關(guān)鍵代碼 1.3

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

    private static final long INIT_CONTROL;
    //靜態(tài)代碼塊
    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以下是業(yè)務(wù)代碼

public void testCasMulti(User user) {
        BigDecimal One = new BigDecimal(1);
        while (true) {
            //先檢查庫存有木有 如果沒有就進(jìn)行下面的操作
            Integer param = (Integer) redisUtil.get("kucun");
            if(param<=0){
                //log.info("停止循環(huán)");
                break;
            }
            int initControlLocal = initControl;
            /**
             * 如果已經(jīng)有線程在進(jìn)行獲取了,則直接放棄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;
            }


            /**
             * 爭奪控制權(quán)
             */
            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;

看下運(yùn)行結(jié)果


image.png
image.png

1.5運(yùn)行過程

1)當(dāng)大量請求過來時,首先由線程池執(zhí)行任務(wù),線程池不斷的把任務(wù)分配給線程,corepoolsize不足,就把任務(wù)緩存到隊(duì)列,隊(duì)列已經(jīng)滿了,就繼續(xù)開線程,直接到最大值max時,就丟棄任務(wù)。
2)線程池執(zhí)行的任務(wù)調(diào)用業(yè)務(wù)層,發(fā)現(xiàn)有一些線程先搶占了任務(wù),其他線程睡眠,或者自旋等待
3)獲取鎖的線程執(zhí)行扣減庫存的任務(wù)

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

參考鏈接

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容