多线程并发导致CPU100%的一种原因和解决办法

时间:2021-03-01 17:57:20

在用自定义线程池的时候,遇到cpu100%,经过验证后,发现问题来源于我定义的子线程。
子线程的主要功能是从任务队列(LinkedBlockingQueue)里面持续拿出任务,并且执行。
以下为令CPU100的代码。

private  class WorkThread extends Thread
{

@Override
public void run()
{
while(flag)
{
Runnable task=null;

if(flag&&!taskQueue.isEmpty())//当队列非空
{
try
{
task=taskQueue.poll();//拿到任务,若没有则拿到null
if(task!=null)
task.run();//执行任务
} catch (Exception e)
{
e.printStackTrace();
}
}
}
}
}

之后,随便往while循环里面添加进System.out.println(“xxxx”);
发现CPU降低了,不会升到100,于是我修改了代码如下:

//增加一句Thread.sleep(),令所有线程每次进入while循环的时候,都先休眠释放资源,这CPU就不会升到100
private class WorkThread extends Thread
{

@Override
public void run()
{
while(flag)
{
try {
Thread.sleep((long) 0.5);//先释放资源,避免cpu占用过高
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}

Runnable task=null;

if(flag&&!taskQueue.isEmpty())//当队列非空
{
try
{
task=taskQueue.poll();//拿到任务,若没有则拿到null
if(task!=null)
task.run();//执行任务
} catch (Exception e)
{
e.printStackTrace();
}
}
}
}
}

造成上述现象的原因:LinkedBlockingQueue是线程安全,当多线程同步从队列里面取出任务,在微观时刻,有且只有一个线程能进入队列中取,因此其他线程阻塞等待,此时各线程都持有cpu资源,不释放,
就造成了大量cpu等待,因而CPU会升高;
值得注意的一点:
LinkedBlockingQueue中取出任务方法有几种,比如take(),poll(),一开始我用take方法,发现运行后,线程资源无法得到释放,后来看了api发现take()是阻塞拿,意思是:线程往队列里面拿任务,
如果队列里面没有任务,则进行等待知道有任务再次唤醒。
而poll()方法则是有任务就拿,没任务就返回null,因此不会出现阻塞等待,若上面代码改成用take方法,同样会出现cpu100的问题,也在于阻塞,同时也会出现线程不被GC回收。