简体   繁体   中英

Concurrentlinkedqueue misses to add data in multithreading environment

In the below code, in extremely rare case (3 in 1 billion executions of QueueThread object) it reaches the below mentioned if block and queue.size turned out be 7999. What could be the possible reason for the same.

 if(q.size()<batchsize){   
     System.out.println("queue size" +q.size());   
 }

Basically it fails to execute queue.add statement but executes all other statements in the thread.

The code snippet is as below.

import java.util.concurrent.ConcurrentLinkedQueue;   
import java.util.concurrent.ExecutorService;   
import java.util.concurrent.Executors;   
import java.util.concurrent.atomic.AtomicInteger;   

public class CLinkQueueTest {   


    public static final int itersize=100000;   
    public static final int batchsize=8000;   
    public static final int poolsize=100;   

    public static void main (String args[]) throws Exception{   
        int j= 0;   
        ExecutorService service = Executors.newFixedThreadPool(poolsize);   
        AtomicInteger counter = new AtomicInteger(poolsize);   
        ConcurrentLinkedQueue<String> q = new ConcurrentLinkedQueue<String>();   
        String s ="abc";   

        while(j<itersize){   
            int k=0;   
            while(k<batchsize){   
                counter.decrementAndGet();   
                service.submit(new QueueThread(counter, q, s));   
                if(counter.get()<=0){   
                    Thread.sleep(5);   
                }   
                k++;   
            }   
            if(j%20 ==0){   
                System.out.println("Iteration no " + j);   
            }   
            while(counter.get() < poolsize){   
                //wait infinitely   
            }   
            if(q.size()<batchsize){   
                System.out.println("queue size" +q.size());   
            }   
            q.clear();   
            j++;               
        }   

        System.out.println("process complete");   
    }   


import java.util.Queue;   
import java.util.concurrent.Callable;   
import java.util.concurrent.ConcurrentLinkedQueue;   
import java.util.concurrent.atomic.AtomicInteger;   

public class QueueThread implements Callable<Boolean> {   

    private AtomicInteger ai;   
    private Queue<String> qu;   
    private String st;   

    public QueueThread(AtomicInteger i, Queue<String> q, String s){   
        ai = i;   
        qu = q;   
        st = s;        
    }   

    @Override  
    public Boolean call() {   
        try{   
            qu.add(st);            
        } catch(Throwable e){   
            e.printStackTrace();   
        }finally{   
            ai.incrementAndGet();   

        }   
        return true;   
    }   

}  

Could it be that the one time that it registers one too few entries in the queue it is because the Executor has not finished its processing?

It is clear that every time QueueThread.call() is called the queue is added to and the AtomicInteger is incremented. All I can think is that one call has not been performed.

Perhaps you could be a little kinder to the system by using something like:

        while(counter.get() < poolsize){   
            //wait infinitely   
            Thread.currentThread().sleep(5);
        }   

but that's just my opinion.

Documentation for ConcurrentLinkedQueue.size method says:

Beware that, unlike in most collections, this method is NOT a constant-time operation. Because of the asynchronous nature of these queues, determining the current number of elements requires an O(n) traversal. Additionally, if elements are added or removed during execution of this method, the returned result may be inaccurate. Thus, this method is typically not very useful in concurrent applications.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM