在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 問答/Java  Linux/ 如何手動擼一個能夠滿足下列并發(fā)的隊列?

如何手動擼一個能夠滿足下列并發(fā)的隊列?

在做puv統(tǒng)計時碰到的一個問題,用戶請求過來會記錄為一個pv,記錄到redis中,但由于pv量太大會給redis造成過大壓力,所以做個緩存,當pv滿10條了發(fā)一次。用了一個隊列ArrayList實現(xiàn),但隊列的插入、刪除在并發(fā)條件下不可行,所以在方法上加了synchronized:

static ArrayList<Object> pvList = new ArrayList<Object>();
public synchronized void countPv(...){
    //........生成一個PV對象
    pvList.add(PV)
    if(pvList.size()>10){
        //前10個加到redis
        addRedis(pvList.subList(0,10))
    }
    //刪除10個
    pvList.subList(0,10).clear();
}

但在壓力測試中,如果已滿負荷的連續(xù)壓測,發(fā)現(xiàn)會丟掉一些pv,可能是synchronized造成的堵塞導(dǎo)致,如何更好的實現(xiàn)這個需求呢?

每10個請求發(fā)一次,而后刪除,同時可以滿足不斷累加

  1. synchronized放到函數(shù)里面估計提升并不大,畢竟add,size,clear方法都必須滿足同步需求
  2. ConcurrnetLinkedQueue, Concurrent...Array刪除、查找的開銷都非常大,而且貌似沒法用于這種場合

p.s. 您能留段偽碼就最好了

回答
編輯回答
薄荷綠

@fengdui 有一句評論說得好,Redis操作要搬出去。

方法一:

// 把10個元素return出去讓外面的調(diào)用者去調(diào)Redis,別占用同步塊的時間
public synchronized List<Object> countPv(...) {
  ...
}

方法二:開個線程池去異步發(fā)Redis,但是機器重啟會丟失來不及發(fā)送的數(shù)據(jù)

if (pvList.size() > 10) {
        //前10個打包成任務(wù)扔給線程池
        senderExecutor.execute(new SendTask(new ArrayList<>(pvList.subList(0,10)))); //當場復(fù)制了subList
        pvList.subList(0,10).clear(); //這行要移到這里,這可能就是你丟數(shù)據(jù)的原因
}
2018年9月14日 20:31
編輯回答
膽怯
2017年1月30日 02:40
編輯回答
深記你

java線程池,怎么樣

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
    final int index = i;
    singleThreadExecutor.execute(new Runnable() {
 
        @Override
        public void run() {
            try {
                // TODO 干你想干的
                addRedis(pvList.subList(0,10))
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    });
}

Java(Android)線程池

2018年6月20日 23:12
編輯回答
臭榴蓮

pipeline ?

2017年2月24日 16:51
編輯回答
乖乖噠

不知道你說的滿負荷壓測時丟pv指的是什么,有沒有記錄這種情況下,服務(wù)器返回的狀態(tài)碼是什么?是因為超時么?
如果是因為壓力過大超出服務(wù)器載能力,換用或其他數(shù)據(jù)結(jié)構(gòu)也不見得好到哪去, 如果想解鎖synchronized, 可能試試多例模式. 每個服務(wù)線程創(chuàng)建自己私有的緩存.

2017年5月23日 15:12
編輯回答
拮據(jù)

不要用synchronized
ConcurrnetLinkedQueue 用法不對 subList(0,10)??? 開個線程從隊尾取 取了10個就 處理
你這10個扔redis搞什么意思 (還不如直接扔redis)
可以扔消息隊列里面 然后異步的處理

貼一段代碼
https://www.cnblogs.com/linji...
運行結(jié)果:
costtime 2360ms

改用while (queue.size()>0)后
運行結(jié)果:
cost time 46422ms

結(jié)果居然相差那么大,看了下ConcurrentLinkedQueue的API原來.size()是要遍歷一遍集合的,難怪那么慢,所以盡量要避免用size而改用isEmpty().

總結(jié)了下, 在單位缺乏性能測試下,對自己的編程要求更加要嚴格,特別是在生產(chǎn)環(huán)境下更是要小心謹慎。

2017年6月30日 12:28
編輯回答
笑忘初
public synchronized void countPv(...){
    //........生成一個PV對象
   
    pvList.add(PV)
    if(pvList.size() > 10){
        addRedis(pvList.subList(0,10))
    }

    pvList.subList(0,10).clear();
}

pvList.subList(0,10).clear(); 這句代碼不應(yīng)該寫到 if 里面嗎?
既然 pvList 是 static 的(類變量),那么 countPV 也應(yīng)該是 static 的才對,這樣 synchronize 使用的鎖才會是 class,而不是對象。

2018年5月12日 20:27