java彙總

Java 相關 3、JVM內存管理和垃圾回收 1)堆html

全部經過new建立的對象的內存都在堆中分配,堆的大小能夠經過-Xmx和-Xms來控制。堆被劃分爲新生代和舊生代,新生代又被進一步劃分爲Eden和Survivor區,最後Survivor由From Space和To Space組成java

新生代。新建的對象都是用新生代分配內存,Eden空間不足的時候,會把存活的對象轉移到Survivor中,新生代大小能夠由-Xmn來控制,也能夠用-XX:SurvivorRatio來控制Eden和Survivor的比例mysql

舊生代。用於存放新生代中通過屢次垃圾回收仍然存活的對象nginx

持久帶(Permanent Space)實現方法區,主要存放全部已加載的類信息,方法信息,常量池等等。可經過-XX:PermSize和-XX:MaxPermSize來指定持久帶初始化值和最大值。Permanent Space並不等同於方法區,只不過是Hotspot JVM用Permanent Space來實現方法區而已,有些虛擬機沒有Permanent Space而用其餘機制來實現方法區。程序員

2)棧web

每一個線程執行每一個方法的時候都會在棧中申請一個棧幀,每一個棧幀包括局部變量區和操做數棧,用於存放這次方法調用過程當中的臨時變量、參數和中間結果。redis

-xss:設置每一個線程的堆棧大小. JDK1.5+ 每一個線程堆棧大小爲 1M,通常來講若是棧不是很深的話, 1M 是絕對夠用了的。算法

3)本地方法棧sql

用於支持native方法的執行,存儲了每一個native方法調用的狀態數據庫

4)方法區

存放了要加載的類信息、靜態變量、final類型的常量、屬性和方法信息。JVM用持久代(Permanet Generation)來存放方法區,可經過-XX:PermSize和-XX:MaxPermSize來指定最小值和最大值

垃圾回收按照基本回收策略分

引用計數(Reference Counting):

比較古老的回收算法。原理是此對象有一個引用,即增長一個計數,刪除一個引用則減小一個計數。垃圾回收時,只用收集計數爲0的對象。此算法最致命的是沒法處理循環引用的問題。

標記-清除(Mark-Sweep):

此算法執行分兩階段。第一階段從引用根節點開始標記全部被引用的對象,第二階段遍歷整個堆,把未標記的對象清除。此算法須要暫停整個應用,同時,會產生內存碎片。

複製(Copying):

此算法把內存空間劃爲兩個相等的區域,每次只使用其中一個區域。垃圾回收時,遍歷當前使用區域,把正在使用中的對象複製到另一個區域中。算法每次只處理正在使用中的對象,所以複製成本比較小,同時複製過去之後還能進行相應的內存整理,不會出現「碎片」問題。固然,此算法的缺點也是很明顯的,就是須要兩倍內存空間。

標記-整理(Mark-Compact):

此算法結合了「標記-清除」和「複製」兩個算法的優勢。也是分兩階段,第一階段從根節點開始標記全部被引用對象,第二階段遍歷整個堆,把清除未標記對象而且把存活對象「壓縮」到堆的其中一塊,按順序排放。此算法避免了「標記-清除」的碎片問題,同時也避免了「複製」算法的空間問題。

JVM分別對新生代和舊生代採用不一樣的垃圾回收機制

新生代的GC:

新生代一般存活時間較短,所以基於Copying算法來進行回收,所謂Copying算法就是掃描出存活的對象,並複製到一塊新的徹底未使用的空間中,對應於新生代,就是在Eden和From Space或To Space之間copy。新生代採用空閒指針的方式來控制GC觸發,指針保持最後一個分配的對象在新生代區間的位置,當有新的對象要分配內存時,用於檢查空間是否足夠,不夠就觸發GC。當連續分配對象時,對象會逐漸從eden到survivor,最後到舊生代。

在執行機制上JVM提供了串行GC(Serial GC)、並行回收GC(Parallel Scavenge)和並行GC(ParNew)

1)串行GC

在整個掃描和複製過程採用單線程的方式來進行,適用於單CPU、新生代空間較小及對暫停時間要求不是很是高的應用上,是client級別默認的GC方式,能夠經過-XX:+UseSerialGC來強制指定

2)並行回收GC

在整個掃描和複製過程採用多線程的方式來進行,適用於多CPU、對暫停時間要求較短的應用上,是server級別默認採用的GC方式,可用-XX:+UseParallelGC來強制指定,用-XX:ParallelGCThreads=4來指定線程數

3)並行GC 與舊生代的併發GC配合使用 舊生代的GC:

舊生代與新生代不一樣,對象存活的時間比較長,比較穩定,所以採用標記(Mark)算法來進行回收,所謂標記就是掃描出存活的對象,而後再進行回收未被標記的對象,回收後對用空出的空間要麼進行合併,要麼標記出來便於下次進行分配,總之就是要減小內存碎片帶來的效率損耗。在執行機制上JVM提供了串行GC(Serial MSC)、並行GC(parallel MSC)和併發GC(CMS),具體算法細節還有待進一步深刻研究。

4、JVM內存調優

首先須要注意的是在對JVM內存調優的時候不能只看操做系統級別Java進程所佔用的內存,這個數值不能準確的反應堆內存的真實佔用狀況,由於GC事後這個值是不會變化的,所以內存調優的時候要更多地使用JDK提供的內存查看工具,好比JConsole和Java VisualVM。

對JVM內存的系統級的調優主要的目的是減小GC的頻率和Full GC的次數,過多的GC和Full GC是會佔用不少的系統資源(主要是CPU),影響系統的吞吐量。特別要關注Full GC,由於它會對整個堆進行整理,致使Full GC通常因爲如下幾種狀況:

舊生代空間不足

調優時儘可能讓對象在新生代GC時被回收、讓對象在新生代多存活一段時間和不要建立過大的對象及數組避免直接在舊生代建立對象

Pemanet Generation空間不足

增大Perm Gen空間,避免太多靜態對象

統計獲得的GC後晉升到舊生代的平均大小大於舊生代剩餘空間

控制好新生代和舊生代的比例 System.gc()被顯示調用

垃圾回收不要手動觸發,儘可能依靠JVM自身的機制

調優手段主要是經過控制堆內存的各個部分的比例和GC策略來實現,下面來看看各部分比例不良設置會致使什麼後果

1)新生代設置太小

一是新生代GC次數很是頻繁,增大系統消耗;二是致使大對象直接進入舊生代,佔據了舊生代剩餘空間,誘發Full GC

2)新生代設置過大

一是新生代設置過大會致使舊生代太小(堆總量必定),從而誘發Full GC;二是新生代GC耗時大幅度增長

通常說來新生代佔整個堆1/3比較合適 3)Survivor設置太小

致使對象從eden直接到達舊生代,下降了在新生代的存活時間

4)Survivor設置過大 致使eden太小,增長了GC頻率

另外,經過-XX:MaxTenuringThreshold=n來控制新生代存活時間,儘可能讓對象在新生代被回收

由內存管理和垃圾回收可知新生代和舊生代都有多種GC策略和組合搭配,選擇這些策略對於咱們這些開發人員是個難題,JVM提供兩種較爲簡單的GC策略的設置方式

1)吞吐量優先

JVM以吞吐量爲指標,自行選擇相應的GC策略及控制新生代與舊生代的大小比例,來達到吞吐量指標。這個值可由-XX:GCTimeRatio=n來設置

2)暫停時間優先

JVM以暫停時間爲指標,自行選擇相應的GC策略及控制新生代與舊生代的大小比例,儘可能保證每次GC形成的應用中止時間都在指定的數值範圍內完成。這個值可由-XX:MaxGCPauseRatio=n來設置

Memcached & Redis 選項對比

4.1 Memcached介紹

Memcached 是一個高性能的分佈式內存對象緩存系統,用於動態Web應用以減輕數據庫負載。它經過在內存中緩存數據和對象來減小讀取數據庫的次數,從而提供動態、數據庫驅動網站的速度,如今已被LiveJournal、hatena、Facebook、Vox、LiveJournal等公司所使用。

4.2 Memcached工做方式分析

許多Web應用都將數據保存到 RDBMS中,應用服務器從中讀取數據並在瀏覽器中顯示。 但隨着數據量的增大、訪問的集中,就會出現RDBMS的負擔加劇、數據庫響應惡化、 網站顯示延遲等重大影響。Memcached是高性能的分佈式內存緩存服務器,經過緩存數據庫查詢結果,減小數據庫訪問次數,以提升動態Web等應用的速度、 提升可擴展性。

Memcached做爲高速運行的分佈式緩存服務器,具備如下的特色:

協議簡單 基於libevent的事件處理 內置內存存儲方式 memcached不互相通訊的分佈式 4.3 如何實現分佈式可拓展性?

Memcached的分佈式不是在服務器端實現的,而是在客戶端應用中實現的,即經過內置算法制定目標數據的節點。

4.4 Redis 介紹

Redis是一個key-value存儲系統。和Memcached相似,它支持存儲的value類型相對更多,包括string(字符串)、 list(鏈表)、set(集合)和zset(有序集合)。這些數據類型都支持push/pop、add/remove及取交集並集和差集及更豐富的操做,並且這些操做都是原子性的。在此基礎上,redis支持各類不一樣方式的排序。與memcached同樣,爲了保證效率,數據都是緩存在內存中。區別的是redis會週期性的把更新的數據寫入磁盤或者把修改操做寫入追加的記錄文件,而且在此基礎上實現了master-slave(主從)同步,當前 Redis的應用已經很是普遍,國內像新浪、淘寶,國外像 Flickr、Github等均在使用Redis的緩存服務。

4.5 Redis 工做方式分析

Redis做爲一個高性能的key-value數據庫具備如下特徵:

多樣的數據模型 持久化 主從同步

Redis支持豐富的數據類型,最爲經常使用的數據類型主要由五種:String、Hash、List、Set和Sorted Set。Redis一般將數據存儲於內存中,或被配置爲使用虛擬內存。Redis有一個很重要的特色就是它能夠實現持久化數據,經過兩種方式能夠實現數據持久化:使用RDB快照的方式,將內存中的數據不斷寫入磁盤;或使用相似MySQL的AOF日誌方式,記錄每次更新的日誌。前者性能較高,可是可能會引發必定程度的數據丟失;後者相反。 Redis支持將數據同步到多臺從數據庫上,這種特性對提升讀取性能很是有益。

4.6 Redis如何實現分佈式可拓展性?

2.8之前的版本:與Memcached一致,能夠在客戶端實現,也能夠使用代理,twitter已開發出用於Redis和Memcached的代理Twemproxy 。

3.0 之後的版本:相較於Memcached只能採用客戶端實現分佈式存儲,Redis則在服務器端構建分佈式存儲。Redis Cluster是一個實現了分佈式且容許單點故障的Redis高級版本,它沒有中心節點,各個節點地位一致,具備線性可伸縮的功能。如圖給出Redis Cluster的分佈式存儲架構,其中節點與節點之間經過二進制協議進行通訊,節點與客戶端之間經過ascii協議進行通訊。在數據的放置策略上,Redis Cluster將整個 key的數值域分紅16384個哈希槽,每一個節點上能夠存儲一個或多個哈希槽,也就是說當前Redis Cluster支持的最大節點數就是16384

5、綜合結論

應該說Memcached和Redis都能很好的知足解決咱們的問題,它們性能都很高,總的來講,能夠把Redis理解爲是對Memcached的拓展,是更加劇量級的實現,提供了更多更強大的功能。具體來講:

1.性能上:

性能上都很出色,具體到細節,因爲Redis只使用單核,而Memcached能夠使用多核,因此平均每個核上Redis在存儲小數據時比

Memcached性能更高。而在100k以上的數據中,Memcached性能要高於Redis,雖然Redis最近也在存儲大數據的性能上進行優化,可是比起 Memcached,仍是稍有遜色。

2.內存空間和數據量大小:

MemCached能夠修改最大內存,採用LRU算法。Redis增長了VM的特性,突破了物理內存的限制。

3.操做便利上:

MemCached數據結構單一,僅用來緩存數據,而Redis支持更加豐富的數據類型,也能夠在服務器端直接對數據進行豐富的操做,這樣能夠減小網絡IO次數和數據體積。

4.可靠性上:

MemCached不支持數據持久化,斷電或重啓後數據消失,但其穩定性是有保證的。Redis支持數據持久化和數據恢復,容許單點故障,可是同時也會付出性能的代價。

5.應用場景:

Memcached:動態系統中減輕數據庫負載,提高性能;作緩存,適合多讀少寫,大數據量的狀況(如人人網大量查詢用戶信息、好友信息、文章信息等)。

Redis:適用於對讀寫效率要求都很高,數據處理業務複雜和對安全性要求較高的系統(如新浪微博的計數和微博發佈部分系統,對數據安全性、讀寫要求都很高)。

6、須要慎重考慮的部分

1.Memcached單個key-value大小有限,一個value最大隻支持1MB,而Redis最大支持512MB

2.Memcached只是個內存緩存,對可靠性無要求;而Redis更傾向於內存數據庫,所以對對可靠性方面要求比較高

3.從本質上講,Memcached只是一個單一key-value內存Cache;而Redis則是一個數據結構內存數據庫,支持五種數據類型,所以Redis除單純緩存做用外,還能夠處理一些簡單的邏輯運算,Redis不只能夠緩存,並且還能夠做爲數據庫用

4.新版本(3.0)的Redis是指集羣分佈式,也就是說集羣自己均衡客戶端請求,各個節點能夠交流,可拓展行、可維護性更強大。

高併發解決方案 二、如何處理併發和同步

今天講的如何處理併發和同同步問題主要是經過鎖機制。

咱們須要明白,鎖機制有兩個層面。

一種是代碼層次上的,如java中的同步鎖,典型的就是同步關鍵字synchronized,這裏我不在作過多的講解,

另一種是數據庫層次上的,比較典型的就是悲觀鎖和樂觀鎖。這裏咱們重點講解的就是悲觀鎖(傳統的物理鎖)和樂觀鎖。

悲觀鎖(Pessimistic Locking):

悲觀鎖,正如其名,它指的是對數據被外界(包括本系統當前的其餘事務,以及來自 外部系統的事務處理)修改持保守態度,所以,

在整個數據處理過程當中,將數據處於鎖定狀態。

悲觀鎖的實現,每每依靠數據庫提供的鎖機制(也只有數據庫層提供的鎖機制才能 真正保證數據訪問的排他性,不然,即便在本系統中實現了加鎖機制,也沒法保證外部系 統不會修改數據)。

一個典型的倚賴數據庫的悲觀鎖調用:

select * from account where name=」Erica」 for update

這條 sql 語句鎖定了 account 表中全部符合檢索條件( name=」Erica」 )的記錄。

本次事務提交以前(事務提交時會釋放事務過程當中的鎖),外界沒法修改這些記錄。

Hibernate 的悲觀鎖,也是基於數據庫的鎖機制實現。

下面的代碼實現了對查詢記錄的加鎖:

String hqlStr ="from TUser as user where user.name='Erica'";

Query query = session.createQuery(hqlStr);

query.setLockMode("user",LockMode.UPGRADE); // 加鎖

List userList = query.list();// 執行查詢,獲取數據

query.setLockMode 對查詢語句中,特定別名所對應的記錄進行加鎖(咱們爲 TUser 類指定了一個別名 「user」 ),這裏也就是對

返回的全部 user 記錄進行加鎖。

觀察運行期 Hibernate 生成的 SQL 語句:

select tuser0_.id as id, tuser0_.name as name, tuser0_.group_id

as group_id, tuser0_.user_type as user_type, tuser0_.sex as sex

from t_user tuser0_ where (tuser0_.name='Erica' ) for update

這裏 Hibernate 經過使用數據庫的 for update 子句實現了悲觀鎖機制。

Hibernate 的加鎖模式有:

Ø LockMode.NONE : 無鎖機制。

Ø LockMode.WRITE : Hibernate 在 Insert 和 Update 記錄的時候會自動獲取

Ø LockMode.READ : Hibernate 在讀取記錄的時候會自動獲取。

以上這三種鎖機制通常由 Hibernate 內部使用,如 Hibernate 爲了保證 Update

過程當中對象不會被外界修改,會在 save 方法實現中自動爲目標對象加上 WRITE 鎖。

Ø LockMode.UPGRADE :利用數據庫的 for update 子句加鎖。

Ø LockMode. UPGRADE_NOWAIT : Oracle 的特定實現,利用 Oracle 的 for

update nowait 子句實現加鎖。

上面這兩種鎖機制是咱們在應用層較爲經常使用的,加鎖通常經過如下方法實現:

Criteria.setLockMode Query.setLockMode Session.lock

注意,只有在查詢開始以前(也就是 Hiberate 生成 SQL 以前)設定加鎖,纔會

真正經過數據庫的鎖機制進行加鎖處理,不然,數據已經經過不包含 for update

子句的 Select SQL 加載進來,所謂數據庫加鎖也就無從談起。

須要注意的是for update要放到mysql的事務中,即begin和commit中,否者不起做用

樂觀鎖(Optimistic Locking):

相對悲觀鎖而言,樂觀鎖機制採起了更加寬鬆的加鎖機制。悲觀鎖大多數狀況下依 靠數據庫的鎖機制實現,以保證操做最大程度的獨佔性。但隨之

而來的就是數據庫 性能的大量開銷,特別是對長事務而言,這樣的開銷每每沒法承受。

如一個金融系統,當某個操做員讀取用戶的數據,並在讀出的用戶數

據的基礎上進 行修改時(如更改用戶賬戶餘額),若是採用悲觀鎖機制,也就意味着整個操做過 程中(從操做員讀出數據、開始修改直至提交修改結果的全

過程,甚至還包括操做 員中途去煮咖啡的時間),數據庫記錄始終處於加鎖狀態,能夠想見,若是面對幾 百上千個併發,這樣的狀況將致使怎樣的後果。

樂觀鎖機制在必定程度上解決了這個問題。

樂觀鎖,大可能是基於數據版本   Version )記錄機制實現。何謂數據版本?即爲數據增長一個版本標識,在基於數據庫表的版本解決方案中,通常是通

過爲數據庫表增長一個 「version」 字段來 實現。 讀取出數據時,將此版本號一同讀出,以後更新時,對此版本號加一。此時,將提 交數據的版本數據與數據

庫表對應記錄的當前版本信息進行比對,若是提交的數據 版本號大於數據庫表當前版本號,則予以更新,不然認爲是過時數據。

四、常見的提升高併發下訪問的效率的手段 首先要了解高併發的的瓶頸在哪裏?

一、多是服務器網絡帶寬不夠 2.可能web線程鏈接數不夠3.可能數據庫鏈接查詢上不去。

根據不一樣的狀況,解決思路也不一樣。

像第一種狀況能夠增長網絡帶寬,DNS域名解析分發多臺服務器。

負載均衡,前置代理服務器nginx、apache等等

數據庫查詢優化,讀寫分離,分表等等

最後複製一些在高併發下面須要經常須要處理的內容:

儘可能使用緩存,包括用戶緩存,信息緩存等,多花點內存來作緩存,能夠大量減小與數據庫的交互,提升性能。

用jprofiler等工具找出性能瓶頸,減小額外的開銷。

優化數據庫查詢語句,減小直接使用hibernate等工具的直接生成語句(僅耗時較長的查詢作優化)。

優化數據庫結構,多作索引,提升查詢效率。

統計的功能儘可能作緩存,或按天天一統計或定時統計相關報表,避免須要時進行統計的功能。

能使用靜態頁面的地方儘可能使用,減小容器的解析(儘可能將動態內容生成靜態html來顯示)。

解決以上問題後,使用服務器集羣來解決單臺的瓶頸問題。

Mysql & Mongodb 對比 1、MySQL的主要適用場景

一、Web網站系統二、日誌記錄系統三、數據倉庫系統四、嵌入式系統

MySQL存儲引擎概述 1)MyISAM存儲引擎 MyISAM支持如下三種類型的索引: 一、B-Tree索引

B-Tree索引,顧名思義,就是全部的索引節點都按照balancetree的數據結構來存儲,全部的索引數據節點都在葉節點。

二、R-Tree索引

R-Tree索引的存儲方式和b-tree索引有一些區別,主要設計用於爲存儲空間和多維數據的字段作索引,因此目前的MySQL版原本說,也僅支持geometry類型的字段做索引。

三、Full-text索引

Full-text索引就是咱們長說的全文索引,他的存儲結構也是b-tree。主要是爲了解決在咱們須要用like查詢的低效問題。

2)Innodb 存儲引擎

一、支持事務安裝二、數據多版本讀取三、鎖定機制的改進四、實現外鍵

3)NDBCluster存儲引擎 4)Merge存儲引擎 5)Memory存儲引擎 5、MySQL 鎖定機制簡介 行級鎖定(row-level) 表級鎖定(table-level) 頁級鎖定(page-level)

在MySQL數據庫中,使用表級鎖定的主要是MyISAM,Memory,CSV等一些非事務性存儲引擎,而使用行級鎖定的主要是Innodb存儲引擎和NDBCluster存儲引擎,頁級鎖定主要是BerkeleyDB存儲引擎的鎖定方式。

6、MySQL Query的優化

Query語句的優化思路和原則主要提如今如下幾個方面:

1. 優化更須要優化的Query; 2. 定位優化對象的性能瓶頸; 3. 明確的優化目標; 4. 從Explain入手; 5. 多使用profile 6. 永遠用小結果集驅動大的結果集; 7. 儘量在索引中完成排序; 8. 只取出本身須要的Columns; 9. 僅僅使用最有效的過濾條件; 10.儘量避免複雜的Join和子查詢; 合理設計並利用索引 MongoDB 更高的寫入負載

默認狀況下,MongoDB更側重高數據寫入性能,而非事務安全,MongoDB很適合業務系統中有大量「低價值」數據的場景。可是應當避免在高事務安全性的系統中使用MongoDB,除非能從架構設計上保證事務安全。

高可用性

MongoDB的復副集(Master-Slave)配置很是簡潔方便,此外,MongoDB能夠快速響應的處理單節點故障,自動、安全的完成故障轉移。這些特性使得MongoDB能在一個相對不穩定(如雲主機)的環境中,保持高可用性。

數據量很大或者將來會變得很大

依賴數據庫(MySQL)自身的特性,完成數據的擴展是較困難的事,在MySQL中,當一個單達表到5-10GB時會出現明顯的性能降級,此時須要經過數據的水平和垂直拆分、庫的拆分完成擴展,使用MySQL一般須要藉助驅動層或代理層完成這類需求。而MongoDB內建了多種數據分片的特性,能夠很好的適應大數據量的需求。

基於位置的數據查詢

MongoDB支持二維空間索引,所以能夠快速及精確的從指定位置獲取數據。

表結構不明確,且數據在不斷變大

在一些傳統RDBMS中,增長一個字段會鎖住整個數據庫/表,或者在執行一個重負載的請求時會明顯形成其它請求的性能降級。一般發生在數據表大於1G的時候(當大於1TB時更甚)。 因MongoDB是文檔型數據庫,爲非結構貨的文檔增長一個新字段是很快速的操做,而且不會影響到已有數據。另一個好處當業務數據發生變化時,是將不在須要由DBA修改表結構。

沒有DBA支持

若是沒有專職的DBA,而且準備不使用標準的關係型思想(結構化、鏈接等)來處理數據,那麼MongoDB將會是你的首選。MongoDB對於對像數據的存儲很是方便,類能夠直接序列化成JSON存儲到MongoDB中。 可是須要先了解一些最佳實踐,避免當數據變大後,因爲文檔設計問題而形成的性能缺陷。

BillRun – 基於MongoDB的賬單系統 (來自oc666)

BillRun是由Ofer Cohen推出開源帳單系統,採用MongoDB作爲數據存儲。這套帳單系統被以色列一家增速最快的電信運營商採用,每個月處理5億條通訊記錄,Ofer在Slideshare上說明了具體利到了MongoDB的哪些特性:

弱數據結構的特色,使得BillRun能很快的支持新的CDR(通信記錄)類型。這個特性使文檔型數據庫很適用於快速發展、業務需求不肯定的系統中。

BillRun僅使用了一個Collection,已經管理了數TB的文檔數據,而且沒有遇到由結構變動、數據爆發式增加的帶來的限制和問題。

replicaSet副本集特性使創建更多的數據中心DRP變得更輕鬆。

內建的Sharding分片特性避免系統在數據增加的過程當中遇到性能瓶頸。

每秒鐘2000條通訊記錄的插入,MongoDB在架構設計上很好的支持了高負載的數據寫入。而且能夠使用findAndModify(相對緩慢)完成基礎的事務特性,而且經過應用層面的支持,實現雙段式提交。

查詢方式相比SQL,更加易讀、易懂,開發相對輕鬆。

基於位置容許更好的分析用戶使用狀況,從而更好地制定移動電話基礎設施的投入點。

消息中間件

Kafka是LinkedIn開源的分佈式發佈-訂閱消息系統,目前歸屬於Apache定級項目。Kafka主要特色是基於Pull的模式來處理消息消費,追求高吞吐量,一開始的目的就是用於日誌收集和傳輸。0.8版本開始支持複製,不支持事務,對消息的重複、丟失、錯誤沒有嚴格要求,適合產生大量數據的互聯網服務的數據收集業務。

RabbitMQ是使用Erlang語言開發的開源消息隊列系統,基於AMQP協議來實現。AMQP的主要特徵是面向消息、隊列、路由(包括點對點和發佈/訂閱)、可靠性、安全。AMQP協議更多用在企業系統內,對數據一致性、穩定性和可靠性要求很高的場景,對性能和吞吐量的要求還在其次。

RocketMQ是阿里開源的消息中間件,它是純Java開發,具備高吞吐量、高可用性、適合大規模分佈式系統應用的特色。RocketMQ思路起源於Kafka,但並非Kafka的一個Copy,它對消息的可靠傳輸及事務性作了優化,目前在阿里集團被普遍應用於交易、充值、流計算、消息推送、日誌流式處理、binglog分發等場景。

測試目的

對比Kafka、RabbitMQ、RocketMQ發送小消息(124字節)的性能。此次壓測咱們只關注服務端的性能指標,因此壓測的標準是:

不斷增長髮送端的壓力,直到系統吞吐量再也不上升,而響應時間拉長。這時服務端已出現性能瓶頸,能夠得到相應的系統最佳吞吐量。

測試場景

在同步發送場景中,三個消息中間件的表現區分明顯:

Kafka的吞吐量高達17.3w/s,不愧是高吞吐量消息中間件的行業老大。這主要取決於它的隊列模式保證了寫磁盤的過程是線性IO。此時broker磁盤IO已達瓶頸。

RocketMQ也表現不俗,吞吐量在11.6w/s,磁盤IO %util已接近100%。RocketMQ的消息寫入內存後即返回ack,由單獨的線程專門作刷盤的操做,全部的消息均是順序寫文件。

RabbitMQ的吞吐量5.95w/s,CPU資源消耗較高。它支持AMQP協議,實現很是重量級,爲了保證消息的可靠性在吞吐量上作了取捨。咱們還作了RabbitMQ在消息持久化場景下的性能測試,吞吐量在2.6w/s左右。

測試結論

在服務端處理同步發送的性能上,Kafka>RocketMQ>RabbitMQ。

實現可靠MQ和去重參考方法

1. 消息的可靠性設計,目前有2種模式:模式1是採用Notify的方式,先發送半消息,業務操做成功後最後提交完整消息,同時提供業務操做的檢查接口,這種模式實現消息的最終一致性;模式2將業務數據和消息數據先都存在業務數據庫裏面,經過數據庫的事務保證一致性,隨後將消息轉發給MQ。模式1的缺點是業務侵入性高,方案比較複雜,須要從新實現;模式2的缺點是消息數據可能會散落在各個地方,包括業務系統,並且能夠集成現有MQ。

2. 消息去重設計,也有2種模式:模式1是消費者根據本身的業務實現去重,模式2是在消費者端增長一個數據庫表專門記錄已經消費過的消息,不須要消費者根據業務去作去重。

單點登陸

只是簡要介紹下基於java的實現過程,不提供完整源碼,明白了原理,我相信大家能夠本身實現。sso採用客戶端/服務端架構,咱們先看sso-client與sso-server要實現的功能(下面:sso認證中心=sso-server)

sso-client

1. 攔截子系統未登陸用戶請求,跳轉至sso認證中心

2. 接收並存儲sso認證中心發送的令牌

3. 與sso-server通訊,校驗令牌的有效性

4. 創建局部會話

5. 攔截用戶註銷請求,向sso認證中心發送註銷請求

6. 接收sso認證中心發出的註銷請求,銷燬局部會話

sso-server 1. 驗證用戶的登陸信息 2. 建立全局會話 3. 建立受權令牌 4. 與sso-client通訊發送令牌 5. 校驗sso-client令牌有效性 6. 系統註冊

7. 接收sso-client註銷請求,註銷全部會話

Lock和synchronized比較詳解

總結一下,也就是說Lock提供了比synchronized更多的功能。可是要注意如下幾點:  1)Lock不是Java語言內置的,synchronized是Java語言的關鍵字,所以是內置特性。Lock是一個類,經過這個類能夠實現同步訪問;

2)Lock和synchronized有一點很是大的不一樣,採用synchronized不須要用戶去手動釋放鎖,當synchronized方法或者synchronized代碼塊執行完以後,系統會自動讓線程釋放對鎖的佔用;而Lock則必需要用戶去手動釋放鎖,若是沒有主動釋放鎖,就有可能致使出現死鎖現象。

二.java.util.concurrent.locks包下經常使用的類

下面來逐個講述Lock接口中每一個方法的使用,lock()、tryLock()、tryLock(long time, TimeUnit unit)和lockInterruptibly()是用來獲取鎖的。

2.ReentrantLock

ReentrantLock,意思是「可重入鎖」,關於可重入鎖的概念在下一節講述。ReentrantLock是惟一實現了Lock接口的類,而且ReentrantLock提供了更多的方法。下面經過一些實例看具體看一下如何使用ReentrantLock。

3.ReadWriteLock

ReadWriteLock也是一個接口,在它裏面只定義了兩個方法:

一個用來獲取讀鎖,一個用來獲取寫鎖。也就是說將文件的讀寫操做分開,分紅2個鎖來分配給線程,從而使得多個線程能夠同時進行讀操做。下面的ReentrantReadWriteLock實現了ReadWriteLock接口。

4.ReentrantReadWriteLock

ReentrantReadWriteLock裏面提供了不少豐富的方法,不過最主要的有兩個方法:readLock()和writeLock()用來獲取讀鎖和寫鎖。

5.Lock和synchronized的選擇

總結來講,Lock和synchronized有如下幾點不一樣:

1)Lock是一個接口,而synchronized是Java中的關鍵字,synchronized是內置的語言實現;

2)synchronized在發生異常時,會自動釋放線程佔有的鎖,所以不會致使死鎖現象發生;而Lock在發生異常時,若是沒有主動經過unLock()去釋放鎖,則極可能形成死鎖現象,所以使用Lock時須要在finally塊中釋放鎖;

3)Lock可讓等待鎖的線程響應中斷,而synchronized卻不行,使用synchronized時,等待的線程會一直等待下去,不可以響應中斷;

4)經過Lock能夠知道有沒有成功獲取鎖,而synchronized卻沒法辦到。

5)Lock能夠提升多個線程進行讀操做的效率。

在性能上來講,若是競爭資源不激烈,二者的性能是差很少的,而當競爭資源很是激烈時(即有大量線程同時競爭),此時Lock的性能要遠遠優於synchronized。因此說,在具體使用時要根據適當狀況選擇。

三.鎖的相關概念介紹 1.可重入鎖

若是鎖具有可重入性,則稱做爲可重入鎖。像synchronized和ReentrantLock都是可重入鎖,可重入性在我看來實際上代表了鎖的分配機制:基於線程的分配,而不是基於方法調用的分配。舉個簡單的例子,當一個線程執行到某個synchronized方法時,好比說method1,而在method1中會調用另一個synchronized方法method2,此時線程沒必要從新去申請鎖,而是能夠直接執行方法method2。

2.可中斷鎖

可中斷鎖:顧名思義,就是能夠相應中斷的鎖。在Java中,synchronized就不是可中斷鎖,而Lock是可中斷鎖。 若是某一線程A正在執行鎖中的代碼,另外一線程B正在等待獲取該鎖,可能因爲等待時間過長,線程B不想等待了,想先處理其餘事情,咱們可讓它中斷本身或者在別的線程中中斷它,這種就是可中斷鎖。

3.公平鎖

公平鎖即儘可能以請求鎖的順序來獲取鎖。好比同是有多個線程在等待一個鎖,當這個鎖被釋放時,等待時間最久的線程(最早請求的線程)會得到該所,這種就是公平鎖。

非公平鎖即沒法保證鎖的獲取是按照請求鎖的順序進行的。這樣就可能致使某個或者一些線程永遠獲取不到鎖。在Java中,synchronized就是非公平鎖,它沒法保證等待的線程獲取鎖的順序。

4.讀寫鎖

讀寫鎖將對一個資源(好比文件)的訪問分紅了2個鎖,一個讀鎖和一個寫鎖。

正由於有了讀寫鎖,才使得多個線程之間的讀操做不會發生衝突。

ReadWriteLock就是讀寫鎖,它是一個接口,ReentrantReadWriteLock實現了這個接口。

多線程和線程池 3、Thread和Runnable的區別

若是一個類繼承Thread,則不適合資源共享。可是若是實現了Runable接口的話,則很容易的實現資源共享。

總結:

實現Runnable接口比繼承Thread類所具備的優點:

1):適合多個相同的程序代碼的線程去處理同一個資源

2):能夠避免java中的單繼承的限制

3):增長程序的健壯性,代碼能夠被多個線程共享,代碼和數據獨立

4):線程池只能放入實現Runable或callable類線程,不能直接放入繼承Thread的類

4、線程狀態轉換

下面的這個圖很是重要!你若是看懂了這個圖,那麼對於多線程的理解將會更加深入!

一、新建狀態(New):新建立了一個線程對象。

二、就緒狀態(Runnable):線程對象建立後,其餘線程調用了該對象的start()方法。該狀態的線程位於可運行線程池中,變得可運行,等待獲取CPU的使用權。

三、運行狀態(Running):就緒狀態的線程獲取了CPU,執行程序代碼。

四、阻塞狀態(Blocked):阻塞狀態是線程由於某種緣由放棄CPU使用權,暫時中止運行。直到線程進入就緒狀態,纔有機會轉到運行狀態。阻塞的狀況分三種:

(一)、等待阻塞:運行的線程執行wait()方法,JVM會把該線程放入等待池中。(wait會釋放持有的鎖)

(二)、同步阻塞:運行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程佔用,則JVM會把該線程放入鎖池中。

(三)、其餘阻塞:運行的線程執行sleep()或join()方法,或者發出了I/O請求時,JVM會把該線程置爲阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程從新轉入就緒狀態。(注意,sleep是不會釋放持有的鎖)

五、死亡狀態(Dead):線程執行完了或者因異常退出了run()方法,該線程結束生命週期。

5、線程調度 線程的調度

一、調整線程優先級:Java線程有優先級,優先級高的線程會得到較多的運行機會。

wait和sleep區別 共同點:

1. 他們都是在多線程的環境下,均可以在程序的調用處阻塞指定的毫秒數,並返回。

2. wait()和sleep()均可以經過interrupt()方法 打斷線程的暫停狀態 ,從而使線程馬上拋出InterruptedException。

若是線程A但願當即結束線程B,則能夠對線程B對應的Thread實例調用interrupt方法。若是此刻線程B正在wait/sleep /join,則線程B會馬上拋出InterruptedException,在catch() {} 中直接return便可安全地結束線程。

須要注意的是,InterruptedException是線程本身從內部拋出的,並非interrupt()方法拋出的。對某一線程調用 interrupt()時,若是該線程正在執行普通的代碼,那麼該線程根本就不會拋出InterruptedException。可是,一旦該線程進入到 wait()/sleep()/join()後,就會馬上拋出InterruptedException 。

不一樣點:

1. Thread類的方法:sleep(),yield()等

Object的方法:wait()和notify()等

2. 每一個對象都有一個鎖來控制同步訪問。Synchronized關鍵字能夠和對象的鎖交互,來實現線程的同步。

sleep方法沒有釋放鎖,而wait方法釋放了鎖,使得其餘線程能夠使用同步控制塊或者方法。

3. wait,notify和notifyAll只能在同步控制方法或者同步控制塊裏面使用,而sleep能夠在任何地方使用

4. sleep必須捕獲異常,而wait,notify和notifyAll不須要捕獲異常

因此sleep()和wait()方法的最大區別是:

sleep()睡眠時,保持對象鎖,仍然佔有該鎖;

而wait()睡眠時,釋放對象鎖。

可是wait()和sleep()均可以經過interrupt()方法打斷線程的暫停狀態,從而使線程馬上拋出InterruptedException(但不建議使用該方法)。

sleep()方法

sleep()使當前線程進入停滯狀態(阻塞當前線程),讓出CUP的使用、目的是不讓當前線程獨自霸佔該進程所獲的CPU資源,以留必定時間給其餘線程執行的機會;

sleep()是Thread類的Static(靜態)的方法;所以他不能改變對象的機鎖,因此當在一個Synchronized塊中調用Sleep()方法是,線程雖然休眠了,可是對象的機鎖並木有被釋放,其餘線程沒法訪問這個對象(即便睡着也持有對象鎖)。

在sleep()休眠時間期滿後,該線程不必定會當即執行,這是由於其它線程可能正在運行並且沒有被調度爲放棄執行,除非此線程具備更高的優先級。

wait()方法

wait()方法是Object類裏的方法;當一個線程執行到wait()方法時,它就進入到一個和該對象相關的等待池中,同時失去(釋放)了對象的機鎖(暫時失去機鎖,wait(long timeout)超時時間到後還須要返還對象鎖);其餘線程能夠訪問;

wait()使用notify或者notifyAlll或者指定睡眠時間來喚醒當前等待池中的線程。

wiat()必須放在synchronized block中,不然會在program runtime時扔出」java.lang.IllegalMonitorStateException「異常

2. 使用線程池的風險

雖然線程池是構建多線程應用程序的強大機制,但使用它並非沒有風險的。用線程池構建的應用程序容易遭受任何其它多線程應用程序容易遭受的全部併發風險,諸如同步錯誤和死鎖,它還容易遭受特定於線程池的少數其它風險,諸如與池有關的死鎖、資源不足和線程泄漏。

2.1 死鎖

任何多線程應用程序都有死鎖風險。當一組進程或線程中的每個都在等待一個只有該組中另外一個進程才能引發的事件時,咱們就說這組進程或線程 死鎖了。死鎖的最簡單情形是:線程 A 持有對象 X 的獨佔鎖,而且在等待對象 Y 的鎖,而線程 B 持有對象 Y 的獨佔鎖,卻在等待對象 X 的鎖。除非有某種方法來打破對鎖的等待(Java 鎖定不支持這種方法),不然死鎖的線程將永遠等下去。

雖然任何多線程程序中都有死鎖的風險,但線程池卻引入了另外一種死鎖可能,在那種狀況下,全部池線程都在執行已阻塞的等待隊列中另外一任務的執行結果的任務,但這一任務卻由於沒有未被佔用的線程而不能運行。當線程池被用來實現涉及許多交互對象的模擬,被模擬的對象能夠相互發送查詢,這些查詢接下來做爲排隊的任務執行,查詢對象又同步等待着響應時,會發生這種狀況。

2.2 資源不足

線程池的一個優勢在於:相對於其它替代調度機制(有些咱們已經討論過)而言,它們一般執行得很好。但只有恰當地調整了線程池大小時纔是這樣的。線程消耗包括內存和其它系統資源在內的大量資源。除了 Thread 對象所需的內存以外,每一個線程都須要兩個可能很大的執行調用堆棧。除此之外,JVM 可能會爲每一個 Java 線程建立一個本機線程,這些本機線程將消耗額外的系統資源。最後,雖然線程之間切換的調度開銷很小,但若是有不少線程,環境切換也可能嚴重地影響程序的性能。

若是線程池太大,那麼被那些線程消耗的資源可能嚴重地影響系統性能。在線程之間進行切換將會浪費時間,並且使用超出比您實際須要的線程可能會引發資源匱乏問題,由於池線程正在消耗一些資源,而這些資源可能會被其它任務更有效地利用。除了線程自身所使用的資源之外,服務請求時所作的工做可能須要其它資源,例如 JDBC 鏈接、套接字或文件。這些也都是有限資源,有太多的併發請求也可能引發失效,例如不能分配 JDBC 鏈接。

2.3 併發錯誤

線程池和其它排隊機制依靠使用 wait() 和 notify() 方法,這兩個方法都難於使用。若是編碼不正確,那麼可能丟失通知,致使線程保持空閒狀態,儘管隊列中有工做要處理。使用這些方法時,必須格外當心。而最好使用現有的、已經知道能工做的實現,例如 util.concurrent 包。

2.4 線程泄漏

各類類型的線程池中一個嚴重的風險是線程泄漏,當從池中除去一個線程以執行一項任務,而在任務完成後該線程卻沒有返回池時,會發生這種狀況。發生線程泄漏的一種情形出如今任務拋出一個 RuntimeException 或一個 Error 時。若是池類沒有捕捉到它們,那麼線程只會退出而線程池的大小將會永久減小一個。當這種狀況發生的次數足夠多時,線程池最終就爲空,並且系統將中止,由於沒有可用的線程來處理任務。

有些任務可能會永遠等待某些資源或來自用戶的輸入,而這些資源又不能保證變得可用,用戶可能也已經回家了,諸如此類的任務會永久中止,而這些中止的任務也會引發和線程泄漏一樣的問題。若是某個線程被這樣一個任務永久地消耗着,那麼它實際上就被從池除去了。對於這樣的任務,應該要麼只給予它們本身的線程,要麼只讓它們等待有限的時間。

2.5 請求過載

僅僅是請求就壓垮了服務器,這種狀況是可能的。在這種情形下,咱們可能不想將每一個到來的請求都排隊到咱們的工做隊列,由於排在隊列中等待執行的任務可能會消耗太多的系統資源並引發資源缺少。在這種情形下決定如何作取決於您本身;在某些狀況下,您能夠簡單地拋棄請求,依靠更高級別的協議稍後重試請求,您也能夠用一個指出服務器暫時很忙的響應來拒絕請求。

5. 經常使用的幾種線程池

5.1 newCachedThreadPool

建立一個可緩存線程池,若是線程池長度超過處理須要,可靈活回收空閒線程,若無可回收,則新建線程。

這種類型的線程池特色是:

• 工做線程的建立數量幾乎沒有限制(其實也有限制的,數目爲Interger. MAX_VALUE), 這樣可靈活的往線程池中添加線程。

• 若是長時間沒有往線程池中提交任務,即若是工做線程空閒了指定的時間(默認爲1分鐘),則該工做線程將自動終止。終止後,若是你又提交了新的任務,則線程池從新建立一個工做線程。

• 在使用CachedThreadPool時,必定要注意控制任務的數量,不然,因爲大量線程同時運行,頗有會形成系統癱瘓。

5.2 newFixedThreadPool

建立一個指定工做線程數量的線程池。每當提交一個任務就建立一個工做線程,若是工做線程數量達到線程池初始的最大數,則將提交的任務存入到池隊列中。

FixedThreadPool是一個典型且優秀的線程池,它具備線程池提升程序效率和節省建立線程時所耗的開銷的優勢。可是,在線程池空閒時,即線程池中沒有可運行任務時,它不會釋放工做線程,還會佔用必定的系統資源。

5.3 newSingleThreadExecutor

建立一個單線程化的Executor,即只建立惟一的工做者線程來執行任務,它只會用惟一的工做線程來執行任務,保證全部任務按照指定順序(FIFO, LIFO, 優先級)執行。若是這個線程異常結束,會有另外一個取代它,保證順序執行。單工做線程最大的特色是可保證順序地執行各個任務,而且在任意給定的時間不會有多個線程是活動的。

5.4 newScheduleThreadPool

建立一個定長的線程池,並且支持定時的以及週期性的任務執行,支持定時及週期性任務執行。

下面是http和https的概念

什麼是HTTPS: HTTPS(Secure Hypertext Transfer Protocol)安全超文本傳輸協議。

它是一個安全通訊通道,它基於HTTP開發,用於在客戶計算機和服務器之間交換信息。它使用安全套接字層(SSL)進行信息交換,簡單來講它是HTTP的 安全版。 它是由Netscape開發並內置於其瀏覽器中,用於對數據進行壓縮和解壓操做,並返回網絡上傳送回的結果。HTTPS實際上應用了Netscape的安 全全套接字層(SSL)做爲HTTP應用層的子層。(HTTPS使用端口443,而不是象HTTP那樣使用端口80來和TCP/IP進行通訊。)SSL使 用40 位關鍵字做爲RC4流加密算法,這對於商業信息的加密是合適的。HTTPS和SSL支持使用X.509數字認證,若是須要的話用戶能夠確認發送者是誰。

HTTPS和HTTP的區別:

https協議須要到ca申請證書,通常免費證書不多,須要交費。

http是超文本傳輸協議,信息是明文傳輸,https 則是具備安全性的ssl加密傳輸協議。

http和https使用的是徹底不一樣的鏈接方式用的端口也不同,前者是80,後者是443。

http的鏈接很簡單,是無狀態的。

HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,要比http協議安全。

HTTPS解決的問題:

1 . 信任主機的問題. 採用https 的server 必須從CA 申請一個用於證實服務器用途類型的證書. 改證書只有用於對應的server 的時候,客戶度纔信任次主機。因此目前全部的銀行系統網站,關鍵部分應用都是https 的,客戶經過信任該證書,從而信任了該主機,其實這樣作效率很低,可是銀行更側重安全。這一點對咱們沒有任何意義,咱們的server 採用的證書無論本身issue 仍是從公衆的地方issue,客戶端都是本身人,因此咱們也就確定信任該server。

2 . 通信過程當中的數據的泄密和被竄改

1)通常意義上的https, 就是 server 有一個證書.

a) 主要目的是保證server 就是他聲稱的server. 這個跟第一點同樣.

b) 服務端和客戶端之間的全部通信,都是加密的.

i. 具體講,是客戶端產生一個對稱的密鑰,經過server 的證書來交換密鑰,通常意義上的握手過程。

ii. 加下來全部的信息往來就都是加密的,第三方即便截獲,也沒有任何意義,由於他沒有密鑰,固然竄改也就沒有什麼意義了。

2)少量對客戶端有要求的狀況下,會要求客戶端也必須有一個證書。

a) 這裏客戶端證書,其實就相似表示我的信息的時候,除了用戶名/密碼, 還有一個CA 認證過的身份,我的證書通常來講上別人沒法模擬的,全部這樣可以更深的確認本身的身份。

b) 目前少數我的銀行的專業版是這種作法,具體證書多是拿U盤做爲一個備份的載體。

技術:

JVM的類加載機制是什麼?有哪些實現方式?

類加載機制:

類的加載指的是將類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法去內,而後在堆區建立一個java.lang.Class對象,用來封裝在方法區內的數據結構。類的加載最終是在堆區內的Class對象,Class對象封裝了類在方法區內的數據結構,而且向Java程序員提供了訪問方法區內的數據結構的接口。

類加載有三種方式: 1)命令行啓動應用時候由JVM初始化加載

2)經過Class.forName()方法動態加載

3)經過ClassLoader.loadClass()方法動態加載

JVM的常見垃圾回收算法?

1)標記-清楚算法:先後線標記處全部須要回收的對象,在標記完成後統一回收有被標記的對象。

2)複製算法:將可用內存按容量劃分爲大小相等的兩塊,每次只使用其中的一塊。當一塊內存用完了,將其存在另一塊上面,而後再把已使用過的內存空間一次清理掉。

3)標記-整理算法:標記過程與「標記-清除」算法同樣,但後續步驟不是直接對可回收對象進行清理,而是讓所一端移動,而後直接清理掉端邊界之外的內存。

4)分代收集算法:通常是把Java堆分爲新生代和老年代,根據各個年代的特色採用最適當的收集算法。新生代都發現有大批對象死去,選用複製算法。老年代中由於對象存活率高,必須使用「標記-清理」或「標記-整理」算法來進行回收。

JVM調優的常見命令行工具備哪些?JVM常見的調優參數有哪些?

(1)JVM調優的常見命令工具包括:

1)jps命令用於查詢正在運行的JVM進程,

2)jstat能夠實時顯示本地或遠程JVM進程中類裝載、內存、垃圾收集、JIT編譯等數據

3)jinfo用於查詢當前運行這的JVM屬性和參數的值。

4)jmap用於顯示當前Java堆和永久代的詳細信息

5)jhat用於分析使用jmap生成的dump文件,是JDK自帶的工具

6)jstack用於生成當前JVM的全部線程快照,線程快照是虛擬機每一條線程正在執行的方法,目的是定位線程出現長時間停頓的緣由。

(2)JVM常見的調優參數包括: -Xmx

指定java程序的最大堆內存, 使用java -Xmx5000M -version判斷當前系統能分配的最大堆內存

-Xms

指定最小堆內存, 一般設置成跟最大堆內存同樣,減小GC

-Xmn

設置年輕代大小。整個堆大小=年輕代大小 + 年老代大小。因此增大年輕代後,將會減少年老代大小。此值對系統性能影響較大,Sun官方推薦配置爲整個堆的3/8。

-Xss

指定線程的最大棧空間, 此參數決定了java函數調用的深度, 值越大調用深度越深, 若值過小則容易出棧溢出錯誤(StackOverflowError)

-XX:PermSize

指定方法區(永久區)的初始值,默認是物理內存的1/64, 在Java8永久區移除, 代之的是元數據區, 由-XX:MetaspaceSize指定

-XX:MaxPermSize

指定方法區的最大值, 默認是物理內存的1/4, 在java8中由-XX:MaxMetaspaceSize指定元數據區的大小

-XX:NewRatio=n

年老代與年輕代的比值,-XX:NewRatio=2, 表示年老代與年輕代的比值爲2:1

-XX:SurvivorRatio=n

Eden區與Survivor區的大小比值,-XX:SurvivorRatio=8表示Eden區與Survivor區的大小比值是8:1:1,由於Survivor區有兩個(from, to)

ConcurrentHashMap加鎖機制是什麼,詳細說一下?

HashTable容器在競爭激烈的併發環境下表現出效率低下的緣由,是由於全部訪問HashTable的線程都必須競爭同一把鎖,那假如容器裏有多把鎖,每一把鎖用於鎖容器其中一部分數據,那麼當多線程訪問容器裏不一樣數據段的數據時,線程間就不會存在鎖競爭,從而能夠有效的提升併發訪問效率,這就是ConcurrentHashMap所使用的鎖分段技術,首先將數據分紅一段一段的存儲,而後給每一段數據配一把鎖,當一個線程佔用鎖訪問其中一個段數據的時候,其餘段的數據也能被其餘線程訪問。

G1收集器簡介?以及它的內存劃分怎麼樣的?

(1)簡介:

Garbage-First(G1,垃圾優先)收集器是服務類型的收集器,目標是多處理器機器、大內存機器。它高度符合垃圾收集暫停時間的目標,同時實現高吞吐量。Oracle JDK 7 update 4 以及更新發布版徹底支持G1垃圾收集器

(2)G1的內存劃分方式:

它是將堆內存被劃分爲多個大小相等的 heap 區,每一個heap區都是邏輯上連續的一段內存(virtual memory). 其中一部分區域被當成老一代收集器相同的角色(eden, survivor, old), 但每一個角色的區域個數都不是固定的。這在內存使用上提供了更多的靈活性

在重寫equals方法時,須要遵循哪些約定,具體介紹一下?

重寫equals方法時須要遵循通用約定:自反性、對稱性、傳遞性、一致性.、非空性

1)自反性

對於任何非null的引用值x,x.equals(x)必須返回true。---這一點基本上不會有啥問題

2)對稱性

對於任何非null的引用值x和y,當且僅當x.equals(y)爲true時,y.equals(x)也爲true。

3)傳遞性

對於任何非null的引用值x、y、z。若是x.equals(y)==true,y.equals(z)==true,那麼x.equals(z)==true。

4) 一致性

對於任何非null的引用值x和y,只要equals的比較操做在對象所用的信息沒有被修改,那麼屢次調用x.eqals(y)就會一致性地返回true,或者一致性的返回false。

5)非空性 全部比較的對象都不能爲空。

Synchronized優化後的鎖機制簡單介紹一下,包括自旋鎖、偏向鎖、輕量級鎖、重量級鎖?

自旋鎖:

線程自旋說白了就是讓cup在作無用功,好比:能夠執行幾回for循環,能夠執行幾條空的彙編指令,目的是佔着CPU不放,等待獲取鎖的機會。若是旋的時間過長會影響總體性能,時間太短又達不到延遲阻塞的目的。

偏向鎖

偏向鎖就是一旦線程第一次得到了監視對象,以後讓監視對象「偏向」這個線程,以後的屢次調用則能夠避免CAS操做

說白了就是置個變量,若是發現爲true則無需再走各類加鎖/解鎖流程。

輕量級鎖:

輕量級鎖是由偏向所升級來的,偏向鎖運行在一個線程進入同步塊的狀況下,當第二個線程加入鎖爭用的時候,偏向鎖就會升級爲輕量級鎖;

重量級鎖

重量鎖在JVM中又叫對象監視器(Monitor),它很像C中的Mutex,除了具有Mutex(0|1)互斥的功能,它還負責實現了Semaphore(信號量)的功能,也就是說它至少包含一個競爭鎖的隊列,和一個信號阻塞隊列(wait隊列),前者負責作互斥,後一個用於作線程同步。

偏向鎖、輕量級鎖、重量級鎖的對比:

Redis和Memcache區別對比?如何選擇這兩個技術?

區別:

1) Redis和Memcache都是將數據存放在內存中,都是內存數據庫。不過memcache還可用於緩存其餘東西,例如圖片、視頻等等。

2)Redis不只僅支持簡單的k/v類型的數據,同時還提供list,set,hash等數據結構的存儲。

3)虛擬內存--Redis當物理內存用完時,能夠將一些好久沒用到的value 交換到磁盤

4)過時策略--memcache在set時就指定,例如set key1 0 0 8,即永不過時。Redis能夠經過例如expire 設定,例如expire name 10

5)分佈式--設定memcache集羣,利用magent作一主多從;redis能夠作一主多從。均可以一主一從

6)存儲數據安全--memcache掛掉後,數據沒了;redis能夠按期保存到磁盤(持久化)

7)災難恢復--memcache掛掉後,數據不可恢復; redis數據丟失後能夠經過aof恢復

8)Redis支持數據的備份,即master-slave模式的數據備份。

選型:

如果簡單的存取key-value這樣的數據用memcache好一些

如果要支持數據持久化,多數據類型(如集合、散列之類的),用列表類型作隊列之類的高級應用,就用redis

Redis的持久化機制是什麼?各自的優缺點?

redis提供兩種持久化機制RDB和AOF機制。

1)RDB持久化方式:是指用數據集快照的方式記錄redis數據庫的全部鍵值對。

優勢:

1.只有一個文件dump.rdb,方便持久化。

2.容災性好,一個文件能夠保存到安全的磁盤。

3.性能最大化,fork子進程來完成寫操做,讓主進程繼續處理命令,因此是IO最大化。

4.相對於數據集大時,比AOF的啓動效率更高。

缺點: 1.數據安全性低。 2)AOF持久化方式:

是指全部的命令行記錄以redis命令請求協議的格式保存爲aof文件。

優勢:

1.數據安全,aof持久化能夠配置appendfsync屬性,有always,每進行一次命令操做就記錄到aof文件中一次。

2.經過append模式寫文件,即便中途服務器宕機,能夠經過redis-check-aof工具解決數據一致性問題。

3.AOF機制的rewrite模式。 缺點: 1.文件會比RDB形式的文件大。 2.數據集大的時候,比rdb啓動效率低。 Mysql的數據庫表鎖、行鎖、頁級鎖?

表級,直接鎖定整張表,在你鎖按期間,其它進程沒法對該表進行寫操做。若是你是寫鎖,則其它進程則讀也不容許

行級,,僅對指定的記錄進行加鎖,這樣其它進程仍是能夠對同一個表中的其它記錄進行操做。

頁級,表級鎖速度快,但衝突多,行級衝突少,但速度慢。因此取了折衷的頁級,一次鎖定相鄰的一組記錄。

數據庫的四大特徵: (1)原子性(Atomicity)

原子性是指事務包含的全部操做要麼所有成功,要麼所有失敗回滾。

(2)一致性(Consistency)

一個事務執行以前和執行以後都必須處於一致性狀態。

(3)隔離性(Isolation)

隔離性是當多個用戶併發訪問數據庫時,好比操做同一張表時,數據庫爲每個用戶開啓的事務,不能被其餘事務的操做所幹擾,多個併發事務之間要相互隔離。

4)持久性(Durability)

持久性是指一個事務一旦被提交了,那麼對數據庫中的數據的改變就是永久性的。

HashMap和HashTable的主要區別是什麼?,二者底層實現的數據結構是什麼?

HashMap和HashTable的區別:

兩者都實現了Map 接口,是將唯一鍵映射到特定的值上;主要區別在於:

1)HashMap 沒有排序,容許一個null 鍵和多個null 值,而Hashtable 不容許;

2)HashMap 把Hashtable 的contains 方法去掉了,改爲containsvalue 和

containsKey,由於contains 方法容易讓人引發誤解;

3)Hashtable 繼承自Dictionary 類,HashMap 是Java1.2 引進的Map 接口的實現;

4)Hashtable 的方法是Synchronize 的,而HashMap 不是,在多個線程訪問Hashtable 時,不須要本身爲它的方法實現同步,而HashMap 就必須爲之提供外同步。Hashtable 和HashMap 採用的hash/rehash 算法大體同樣,因此性能不會有很大的差別。

HashMap和HashTable的底層實現數據結構:

HashMap和Hashtable的底層實現都是數組+鏈表結構實現的

Java的虛擬機JVM的兩個內存:棧內存和堆內存的區別是什麼?

Java把內存劃分紅兩種:一種是棧內存,一種是堆內存。二者的區別是:

1)棧內存:在函數中定義的一些基本類型的變量和對象的引用變量都在函數的棧內存中分配。 當在一段代碼塊定義一個變量時,Java就在棧中爲這個變量分配內存空間,當超過變量的做用域後,Java會自動釋放掉爲該變量所分配的內存空間,該內存空間能夠當即被另做他用。

2)堆內存:堆內存用來存放由new建立的對象和數組。在堆中分配的內存,由Java虛擬機的自動垃圾回收器來管理。

Java中對異常是如何進行分類的? 異常總體分類:

1)Java異常結構中定義有Throwable類。 Exception和Error爲其子類。

2)其中Exception表示因爲網絡故障、文件損壞、設備錯誤、用戶輸入非法狀況致使的異常;

3)而Error標識Java運行時環境出現的錯誤,例如:JVM內存耗盡。

Java中的線程池共有幾種? Java四種線程池

第一種:newCachedThreadPool

建立一個可根據須要建立新線程的線程池,可是在之前構造的線程可用時將重用它們。

第二種:newFixedThreadPool

建立一個指定工做線程數量的線程池

第三種:newScheduledThreadPool

建立一個線程池,它可安排在給定延遲後運行命令或者按期地執行。

第四種:newSingleThreadExecutor

建立一個使用單個 worker 線程的 Executor,以無界隊列方式來運行該線程。

volatile和synchronized區別

volatile和synchronized簡介:

在Java中,爲了保證多線程讀寫數據時保證數據的一致性,能夠採用兩種方式:

1)使用synchronized關鍵字

2)使用volatile關鍵字:用一句話歸納volatile,它可以使變量在值發生改變時能儘快地讓其餘線程知道。

二者的區別:

1)volatile本質是在告訴jvm當前變量在寄存器中的值是不肯定的,須要從主存中讀取,synchronized則是鎖定當前變量,只有當前線程能夠訪問該變量,其餘線程被阻塞住.

2)volatile僅能使用在變量級別,synchronized則能夠使用在變量,方法.

3)volatile僅能實現變量的修改可見性,而synchronized則能夠保證變量的修改可見性和原子性.

4)volatile不會形成線程的阻塞,而synchronized可能會形成線程的阻塞.

排序都有哪幾種方法?請列舉。用JAVA 實現一個快速排序。

排序的方法有:

插入排序(直接插入排序、希爾排序),交換排序(冒泡排序、快速排序),選擇排序(直接選擇排序、堆排序),歸併排序,分配排序(箱排序、基數排序);

相關文章
相關標籤/搜索