多線程併發導致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回收。
--------------------- 
作者:Tardis1 
來源:CSDN 
原文:https://blog.csdn.net/tardis1/article/details/51693196 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章