ThreadPoolExecutor - ArrayBlockingQueue … to wait

2019-08-15 11:10发布

问题:

I am trying to Tune a thread which does the following:

A thread pool with just 1 thread [CorePoolSize =0, maxPoolSize = 1]

The Queue used is a ArrayBlockingQueue

Quesize = 20

BackGround:
The thread tries to read a request and perform an operation on it.

HOWEVER, eventually the requests have increased so much that the thread is always busy and consume 1 CPU which makes it a resource hog.

What I want to do it , instead sample the requests at intervals and process them . Other requests can be safely ignored.

What I would have to do is put a sleep in "operation" function so that for each task the thread sleeps for sometime and releases the CPU.

Quesiton:
However , I was wondering if there is a way to use a queue which basically itself sleeps for sometime before it reads the next element. This would be ideal since sleeping a task in the middle of execution and keeping the execution incomplete just doesn't sound the best to me.

Please let me know if you have any other suggestions as well for the tasks

Thanks.

Edit: I have added a follow-up question here corrected the maxpool size to be 1 [written in a haste] .. thanks tim for pointing it out.

回答1:

No, you can't make the thread sleep while it's in the pool. If there's a task in the queue, it will be executed.

Pausing within a queued task is the only way to force the thread to be idle in spite of queued tasks. Now, the "sleep" doesn't have to be in the same task as the "work"—you could queue a separate rest task after each real task, which might make for a cleaner implementation. More importantly, if the work is a Callable that returns a result, separating into two tasks will allow you to obtain the result as soon as possible.

As a refinement, rather than sleeping for a fixed interval between every task, you could "throttle" execution to a specified rate. This would allow you to avoid waiting unnecessarily between tasks, yet avoid executing too many tasks within a specified time interval. You can read another answer of mine for a simple way to implement this with a DelayQueue.



回答2:

You could subclass ThreadPool and override beforeExecute to sleep for some time:

@Overrides
protected void beforeExecute(Thread t,
                         Runnable r){
    try{
       Thread.sleep( millis);  // will sleep the correct thread, see JavaDoc
    }
    catch (InterruptedException e){}

  }

But see AngerClown's comment about artificially slowing down the queue probably not being a good idea.



回答3:

This might not work for you, but you could try setting the executor's thread priority to low.

Essentially, create the ThreadPoolExecutor with a custom ThreadFactory. Have the ThreadFactory.newThread() method return Threads with a priority of Thread.MIN_PRIORITY. This will cause the executor service you use to only be scheduled if there is an available core to run it.

The implication: On a system that strictly uses time slicing, you will only be given a time slice to execute if there is no other Thread in the entire program with a greater priority asking to be scheduled. Depending on how busy your application really is, you might get scheduled every once in awhile, or you might not be scheduled at all.



回答4:

The reason the thread is consuming 100% CPU is because it is given more work than it can process. Adding a delay between tasks is not going to fix this problem. It is just make things worse.

Instead you should look at WHY your tasks are consuming so much CPU e.g. with a profiler and change them so that consume less CPU until you find that your thread can keep up and it no longer consumes 100% cpu.