即便是單核處理器也支持多線程執行代碼,CPU 經過給每一個線程分配 CPU 時間片來執行任務,當前任務執行一個時間片後會切換到下一個任務,因此 CPU 經過不停的切換線程執行。java
併發執行若是沒有達到必定的數量級,速度反而會比串行執行要慢。這是由於線程有建立和上下文切換的開銷。程序員
如何減小線程建立和上下文切換的開銷?(「vmstat 1」 的 cs 參數,查看線程切換的次數)算法
如何避免死鎖?數據庫
在Java SE 1.6中,鎖一共有4種狀態,級別從低到高依次是:無鎖狀態、偏向鎖狀態、輕量級鎖狀態和重量級鎖(也稱互斥鎖)狀態,這幾個狀態會隨着競爭狀況逐漸升級。鎖能夠升級但不能降級,這種策略的目的是爲了提升得到鎖和釋放鎖的效率。有意思的是除了偏向鎖,JVM 實現鎖的方式都用了循環 CAS,即當一個線程想進入同步塊的時候使用循環 CAS 的方式來獲取鎖,當它退出同步塊的時候使用循環 CAS 釋放鎖。
若是隻有一個線程進入同步代碼塊,那麼它首先會得到「偏向鎖」;當存在線程間競爭的時候,「偏向鎖」會撤銷,從而使用「輕量級鎖」;當線程經過自旋方式始終獲取不到「輕量級鎖」時(獲取鎖的線程執行時間過長等緣由),那麼「輕量級鎖」會膨脹成「重量級鎖」。編程
JMM(Java 內存模型)採用共享內存模型,經過控制主內存(Main Memory)與每一個線程的本地內存(Local Memory)之間的交互,來爲 Java 程序員提供內存可見性保證。緩存
從 Java 源代碼到最終實際執行的指令序列,會分別經歷「編譯器優化的重排序」、「指令級並行的重排序」、「內存系統的重排序」,前一個屬於編譯器重排序,後兩個屬於處理器重排序,這些重排序會致使多線程程序出現內存可見性問題。爲了保證內存可見性,Java 編譯器在生成指令序列的適當位置會插入內存屏障指令來禁止特定類型的處理器重排序。JMM 把內存屏障分爲四類:
服務器
happens-before 是 JMM 最核心的概念。happens-before 規則對應於一個或多個編譯器和處理器重排序規則,JMM 經過 happens-before 規則隱藏了複雜的重排序規則以及這些規則的具體實現,而程序員在 happens-before 規則上編程,從而保證內存可見性。多線程
順序一致性內存模型是一個理論參考模型,JMM 和處理器內存模型在設計時一般會以順序一致性內存模型爲參照。併發
順序一致性模型、JMM、處理器內存模型,內存模型設計由強變弱,由於越是追求性能,內存模型就會設計的越弱,以此減小內存模型對它們的束縛。app
理解 volatile 特性的一個好方法是把對 volatile 變量的單個讀/寫,當作是使用同一個鎖對這些單個讀/寫操做作了同步。簡而言之,volatile 變量自身具備下列特性:
volatile 關鍵字如何保證可見性?volatile 的內存語義?
volatile 關鍵字如何保證有序性?
爲何 JDK 文檔說 CAS 同時具備 volatile 讀和 volatile 寫的內存語義?
Synchonized 關鍵字的原理?JVM 基於進入和退出 Monitor 對象來實現方法同步和代碼塊同步,但二者的實現細節不同。代碼塊同步是使用 monitorenter 和 monitorexit 指令實現的,而方法同步是使用另一種方式實現的,細節在 JVM 規範裏並無詳細說明。
鎖的釋放和獲取的內存語義?
對於 final 變量,編譯器和處理器要遵照兩個重排序規則(對象引用不在構造函數中「溢出」的狀況下):
final 變量的內存語義?
在構造函數內部,不能讓這個被構造對象的引用爲其餘線程所見,也就是對象引用不能在構造函數中「溢出」。由於 JMM 沒法保證在構造函數中「對變量的寫」和「被構造對象的引用」 這二者之間是否會被重排序。
jps 和 jstack 命令?
jstack 18023 > /home/wwwroot/dump18023
grep java.lang.Thread.State dump18023 | awk '{print $2$3$4$5}' | sort | uniq -c
可使用ODPS、Hadoop 或者本身搭建服務器集羣來解決硬件資源限制的問題。
一個對象的引用佔 4 個字節。