JAVA代碼優化之對for循環嵌套的優化


  場景 : 最近,有客戶反應某些功能執行得很慢,我們於是對代碼日志進行了定位,我們的系統架構是nginx+tomcat; 我們可以直接定位到tomcat的catalina日志,但是后來吧,我們這邊統一要整理響應時間超過5S以上的,對這些都要進行整改;所以我們先直接分析nginx的日志文件,查看請求跟響應超過5S以上的統計出來,然后在tomcat的日志當中定位這些請求,查找到具體的時間,以及上下文,最后我們定位到某個方法執行超過一些時間的(比如一個方法超過2S了,這肯定不行啦)。

  現在,我們拋開掉業務場景,從最近本的優化方案看。

        轉載自 :https://www.cnblogs.com/snifferhu/p/4600321.html


 

 1. 嵌套循環應該內大外小,還是內小外大?

  內大外小指的是 : 內層循環比外層循環次數多。

  代碼實例 : 

       

    @Test 
    public  void testForNeiWai() {
        // 方法說明 : 測試內外循環
        // 1. 測試外循環比內循環大
        Long startTime = System.nanoTime();
        for (int  i = 0; i<1000000; i++){
            for ( int j = 0; j<100 ; j++){
                
            }
        }
        Long endTime = System.nanoTime();
        System.out.println("外大內小耗時: "+(endTime-startTime));
    }

  這里我們運行3次,取3次結果的平均值 : (我這里是8G內存,普通的筆記本,沒有SSD什么的)

  運行時間為 :  外大內小耗時: 325459668; 外大內小耗時: 168779176; 外大內小耗時: 317150703;

  平均耗時為 : 270463182.33333~

  接下來,我們看下,外小內大的情況:   

    @Test 
    public  void testForWaiNei() {
        // 方法說明 : 測試內外循環
        // 1. 測試外循環比內循環小
        Long startTime = System.nanoTime();
        for (int  i = 0; i<100; i++){
            for ( int j = 0; j<1000000 ; j++){
                
            }
        }
        Long endTime = System.nanoTime();
        System.out.println("內大外小耗時: "+(endTime-startTime));
    }

   運行的結果是:內大內外耗時: 355928863; 內大內外耗時: 353038045; 內大內外耗時: 352683093;

        結果為 : 353883333.666~

        由此可見,其實相差這么多倍其實差距並不是太大。雖然網上要求我們堅持外小內大的原則,實際上可能應該按當時的業務場景+測試來得到最終的方案吧。

  2. 提取與循環無關的表達式

    @Test 
    public  void testForWuGuan() {
        // 方法說明 : 測試內外循環
        // 1. 測試外循環比內循環小
        int a = 10,b=12;
        Long startTime = System.nanoTime();
        for ( int j = 0; j<1000000 ; j++){
            j = j*a*b;
        }
        Long endTime = System.nanoTime();
        System.out.println("耗時: "+(endTime-startTime));
    }

  同理,運行的結果是: 內大內外耗時: 21758;內大內外耗時: 14931; 內大內外耗時: 17065

  我們大致定位到這是 18000;我們再看下把a*b提取出去之后的 : 

  同理,運行時間是:耗時: 13652;耗時: 15785;耗時: 14078;這個耗時現在看是減少了一些,然后如果你這個里面有很多這種無關循環的表達式的話,那確實可以提升性能。

  3. 消除循環終止判斷時的方法調用

@Test 
    public  void testForWuXunHuanBianLiang() {
        String sql  = "select * from in_applyinfo where status_lookup_code='140' allow filtering";
        List<ApplyInfoMigration> applyInfoMigrationList = applyInfoDao.selectList(sql,ApplyInfoMigration.class );   // A實體
        int a = 10,b=12, c=a*b;
        Long startTime = System.nanoTime();
        for ( int j = 0; j<applyInfoMigrationList.size() ; j++){
            // j = j*c;
        }
        Long endTime = System.nanoTime();
        System.out.println("耗時: "+(endTime-startTime));
    }

  同理 :  耗時: 37116;耗時: 34556; 耗時: 38397;平均:37000;現在讓我們把上面的list.size()使用一個常量來代替,然后看執行結果是多少。

  同理: 耗時: 14505;耗時: 17492; 耗時: 14506;由此可見,此性能提升了多少,相信大家都有數了,不要讓這一點點代碼而影響我們這么多性能。

  4. 對異常進行優化

    @Test 
    public  void testForException() {
        // 方法說明 : 測試for循環優化
        Long startTime = System.nanoTime();
        for ( int j = 0; j<1000000 ; j++){
            try {
                
            }catch (Exception e){
                
            }
        }
        Long endTime = System.nanoTime();
        System.out.println("耗時: "+(endTime-startTime));
    }

  同理 : 耗時: 4753466; 耗時: 6354166; 耗時: 5265843。接下來,我們把try-catch語句塊移到外面 :

@Test 
    public  void testForExceptionTwo() {
        // 方法說明 : 測試for循環優化
        Long startTime = System.nanoTime();
        try {
            for ( int j = 0; j<1000000 ; j++){
                
            }
        }catch (Exception e){
            
        }
        Long endTime = System.nanoTime();
        System.out.println("耗時: "+(endTime-startTime));
    }

  同理 : 耗時: 4925822 ;耗時: 5144255; 耗時: 5748358; 若我們把代碼放到一堆比較的話 :

  耗時: 7290610 (catch在里面)、4804234
  耗時: 3249610  (catch在外面)  、3632720; 從我這里看性能並沒有多大的提升,可能是也沒有中間業務處理流程,也可能是個人的junit測試環境問題,總之,感覺這里並沒太大的提升。不過對於上面的我覺得可能是jdk1.8版本所導致的吧,所以還是根據個人使用環境來,那么我這里就采取把list的size變為常量來吧。

  5. 說完了上面的for循環基本的優化之后,我覺得實際上還是各自測試下,按照自己當前的業務跟jdk版本來確定優化策略,然后下面我想說一下的是把for循環變為多線程來優化。

       --> 后續補充

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM