日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

人人都能掌握的Java服务端性能优化方案

發布時間:2023/12/3 java 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 人人都能掌握的Java服务端性能优化方案 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載自?人人都能掌握的Java服務端性能優化方案

作為一個Java后端開發,我們寫出的大部分代碼都決定著用戶的使用體驗。如果我們的代碼性能不好,那么用戶在訪問我們的網站時就要浪費一些時間等待服務器的響應。這就可能導致用戶投訴甚至用戶的流失。

關于性能優化是一個很大的話題。《Java程序性能優化》說性能優化包含五個層次:設計調優、代碼調優、JVM調優、數據庫調優、操作系統調優等。而每一個層次又包含很多方法論和最佳實踐。本文不想大而廣的概述這些內容。只是舉幾個常用的Java代碼優化方案,讀者看完之后可以真正的實踐到自己代碼中的方案。

使用單例

對于IO處理、數據庫連接、配置文件解析加載等一些非常耗費系統資源的操作,我們必須對這些實例的創建進行限制,或者是始終使用一個公用的實例,以節約系統開銷,這種情況下就需要用到單例模式。

public?class?Singleton?{ ?
? ?private?volatile?static?Singleton singleton; ?
? ?private?Singleton?(){} ?
? ?public?static?Singleton?getSingleton()?{ ?
? ?if?(singleton ==?null) { ?
? ? ? ?synchronized?(Singleton.class) { ?
? ? ? ?if?(singleton ==?null) { ?
? ? ? ? ? ?singleton =?new?Singleton(); ?
? ? ? ?} ?
? ? ? ?} ?
? ?} ?
? ?return?singleton; ?
? ?} ?
}

單例模式有很多種寫法,我的公眾號也推送過多篇和單例相關的文章:

單例模式的七種寫法

設計模式(二)——單例模式

設計模式(三)——JDK中的那些單例

不使用synchronized和lock,如何實現一個線程安全的單例?

不使用synchronized和lock,如何實現一個線程安全的單例?(二)

深度解析單例與序列化之間的愛恨情仇~

使用線程池

合理利用線程池能夠帶來三個好處。

第一:降低資源消耗。通過重復利用已創建的線程降低線程創建和銷毀造成的消耗。

第二:提高響應速度。當任務到達時,任務可以不需要等到線程創建就能立即執行。

第三:提高線程的可管理性。線程是稀缺資源,如果無限制的創建,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的分配,調優和監控。

在 Java 5 之后,并發編程引入了一堆新的啟動、調度和管理線程的API。Executor 框架便是 Java 5 中引入的,其內部使用了線程池機制,它在 java.util.cocurrent 包下,通過該框架來控制線程的啟動、執行和關閉,可以簡化并發編程的操作。

public?class?MultiThreadTest?{
??public?static?void?main(String[] args)?{
? ? ? ThreadFactory threadFactory =?new?ThreadFactoryBuilder().setNameFormat("thread-%d").build();
? ? ? ExecutorService executor =?new?ThreadPoolExecutor(2,?5,?60L, TimeUnit.SECONDS,?new?LinkedBlockingQueue<Runnable>(), threadFactory);
? ? ? executor.execute(new?Runnable() {
? ? ? ? ? @Override
? ? ? ? ??public?void?run()?
{
? ? ? ? ? ? ?System.out.println("hello world !");
? ? ? ? ? }
? ? ? });
? ? ? System.out.println(" ===> main Thread! "?);
? }
}使用Future模式

假設一個任務執行起來需要花費一些時間,為了省去不必要的等待時間,可以先獲取一個“提貨單”,即Future,然后繼續處理別的任務,直到“貨物”到達,即任務執行完得到結果,此時便可以用“提貨單”進行提貨,即通過Future對象得到返回值。

public?class?RealData?implements?Callable<String>?{ ?
? ?protected?String data; ?

? ?public?RealData(String data)?{ ?
? ? ? ?this.data = data; ?
? ?} ?

? ?@Override??
? ?public?String?call()?throws?Exception?{ ?
? ? ? ?//利用sleep方法來表示真是業務是非常緩慢的 ?
? ? ? ?try?{ ?
? ? ? ? ? ?Thread.sleep(1000); ?
? ? ? ?}?catch?(InterruptedException e) { ?
? ? ? ? ? ?e.printStackTrace(); ?
? ? ? ?} ?
? ? ? ?return?data; ?
? ?} ?
} ?

public?class?Application?{ ?
? ?public?static?void?main(String[] args)?throws?Exception?{ ?
? ? ? ?FutureTask<String> futureTask = ??
? ? ? ? ? ? ? ?new?FutureTask<String>(new?RealData("name")); ?
? ? ? ?ExecutorService executor = ??
? ? ? ? ? ? ? ?Executors.newFixedThreadPool(1);?//使用線程池 ?
? ? ? ?//執行FutureTask,相當于上例中的client.request("name")發送請求 ?
? ? ? ?executor.submit(futureTask); ?
? ? ? ?//這里可以用一個sleep代替對其他業務邏輯的處理 ?
? ? ? ?//在處理這些業務邏輯過程中,RealData也正在創建,從而充分了利用等待時間 ?
? ? ? ?Thread.sleep(2000); ?
? ? ? ?//使用真實數據 ?
? ? ? ?//如果call()沒有執行完成依然會等待 ?
? ? ? ?System.out.println("數據="?+ futureTask.get()); ?
? ?} ?
}使用NIO

JDK自1.4起開始提供全新的I/O編程類庫,簡稱NIO,其不但引入了全新高效的Buffer和Channel,同時,還引入了基于Selector的非阻塞 I/O機制,將多個異步的I/O操作集中到一個或幾個線程當中進行處理,使用NIO代替阻塞I/O能提高程序的并發吞吐能力,降低系統的開銷。

對于每一個請求,如果單獨開一個線程進行相應的邏輯處理,當客戶端的數據傳遞并不是一直進行,而是斷斷續續的,則相應的線程需要 I/O等待,并進行上下文切換。而使用NIO引入的Selector機制后,可以提升程序的并發效率,改善這一狀況。

public?class?NioTest?{ ?
? ?static?public?void?main(?String args[]?) throws Exception?{ ?
? ? ? ?FileInputStream fin =?new?FileInputStream("c:\\test.txt"); ?
? ? ? ?// 獲取通道 ?
? ? ? ?FileChannel fc = fin.getChannel(); ?
? ? ? ?// 創建緩沖區 ?
? ? ? ?ByteBuffer buffer = ByteBuffer.allocate(1024); ?
? ? ? ?// 讀取數據到緩沖區 ?
? ? ? ?fc.read(buffer); ?
? ? ? ?buffer.flip(); ?
? ? ? ?while?(buffer.remaining()>0) { ?
? ? ? ? ? ?byte?b = buffer.get(); ?
? ? ? ? ? ?System.out.print(((char)b)); ?
? ? ? ?} ?
? ? ? ?fin.close(); ?
? ?} ?
}鎖優化

在并發場景中,我們的代碼中經常會用到鎖。存在鎖,就必然存在鎖的競爭,存在鎖的競爭,就會消耗很多資源。那么,如何優化我們Java代碼中的鎖呢?主要可以從以下幾個方面考慮:

  • 減少鎖持有時間

    • 可以使用同步代碼塊來代替同步方法。這樣既可以減少鎖持有的時間。

  • 減少鎖粒度

    • 要在并發場景中使用Map的時候,記得使用ConcurrentHashMap來代替HashTable和HashMap。

  • 鎖分離

    • 普通鎖(如syncronized)會導致讀阻塞寫、寫也會阻塞讀,同時讀讀與寫寫之間也會進行阻塞,可以想辦法將讀操作和寫操作分離開。

  • 鎖粗化

    • 有些情況下我們希望把很多次鎖的請求合并成一個請求,以降低短時間內大量鎖請求、同步、釋放帶來的性能損耗。

  • 鎖消除

    • 鎖消除是Java虛擬機在JIT編譯是,通過對運行上下文的掃描,去除不可能存在共享資源競爭的鎖,通過鎖消除,可以節省毫無意義的請求鎖時間。?

關于鎖優化的內容,后面會出一篇文章詳細介紹。

壓縮傳輸

在進行數據傳輸之前,可以先將數據進行壓縮,以減少網絡傳輸的字節數,提升數據傳輸的速度,接收端可以將數據進行解壓,以還原出傳遞的數據,并且,經過壓縮的數據還可以節約所耗費的存儲介質(磁盤或內存)的空間以及網絡帶寬,降低成本。當然,壓縮也并不是沒有開銷的,數據壓縮需要大量的CPU計算,并且,根據壓縮算法的不同,計算的復雜度以及數據的壓縮比也存在較大差異。一般情況下,需要根據不同的業務場景,選擇不同的壓縮算法。

緩存結果

對于相同的用戶請求,如果每次都重復的查詢數據庫,重復的進行計算,將浪費很多的時間和資源。將計算后的結果緩存到本地內存,或者是通過分布式緩存來進行結果的緩存,可以節約寶貴的CPU計算資源,減少重復的數據庫查詢或者是磁盤I/O,將原本磁頭的物理轉動變成內存的電子運動,提高響應速度,并且線程的迅速釋放也使得應用的吞吐能力得到提升。


總結

以上是生活随笔為你收集整理的人人都能掌握的Java服务端性能优化方案的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。