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

在用自定义线程池的时候,遇到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回收。

猜你喜欢

转载自blog.csdn.net/Tardis1/article/details/51693196
今日推荐