Java之戳中痛點之 synchronized 深度解析|java|override|author|...

2021-01-07 網易

  It has not been the time yet to give up as long as you still feel it is not the end. I could cry for a thousand times if you promise me a happy ending.

  只要心裡還存著不甘心,就還不到放棄的時候。只要是喜劇收尾,過程你讓我怎麼哭都行。

  每日掏心話

  人生就像一口大鍋,當你走到了鍋底時,無論朝哪個方向走,都是向上的。最困難的時刻也許就是拐點的開始,改變一下思維方式就可能迎來轉機。

  來自:Json_wangqiang | 責編:樂樂

  連結:cnblogs.com/JsonShare/p/11433302.html

  往日回顧:

  正文

  概覽:

  

  簡介:作用、地位、不控制並發的影響

  

  用法:對象鎖和類鎖

  

  多線程訪問同步方法的7種情況

  

  性質:可重入、不可中斷

  

  原理:加解鎖原理、可重入原理、可見性原理

  

  缺陷:效率低、不夠靈活、無法預判是否成功獲取到鎖

  

  如何選擇Lock或Synchronized

  

  如何提高性能、JVM如何決定哪個線程獲取鎖

  

  總結

  

  後續會有代碼演示,測試環境 JDK8、IDEA

  一、簡介

  1、作用

  能夠保證在同一時刻最多只有一個線程執行該代碼,以保證並發安全的效果。

  2、地位

  

3、不控制並發的影響

  測試:兩個線程同時a++,猜一下結果

  package cn.jsonshare.java.base.synchronizedtest;

  /**
* 不使用synchronized,兩個線程同時a++
*
* @author JSON
*/
public class SynchronizedTest1 implements Runnable{
static SynchronizedTest1 st = new SynchronizedTest1();

  static int a = 0;

  /**
* 不使用synchronized,兩個線程同時a++
*/
public static void main(String[] args) throws Exception{
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(a);
}

  @Override
public void run(){
for(int i=0; i<10000; i++){
a++;
}
}
}

  預期是20000,但多次執行的結果都小於20000

  10108
11526
10736
...

二、用法:對象鎖和類鎖

  1、對象鎖

  

package cn.jsonshare.java.base.synchronizedtest;

  /**
* 對象鎖實例: 代碼塊形式
*
* @author JSON
*/
public class SynchronizedTest2 implements Runnable{
static SynchronizedTest2 st = new SynchronizedTest2();

  public static void main(String[] args) {
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
while(t1.isAlive() || t2.isAlive()){

  }
System.out.println("run over");

  }

  @Override
public void run(){
synchronized (this){
System.out.println("開始執行:" + Thread.currentThread().getName());
try {
// 模擬執行內容
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("執行結束:" + Thread.currentThread().getName());
}
}
}

  package cn.jsonshare.java.base.synchronizedtest;

  /**
* 對象鎖實例:synchronized方法
* @author JSON
*/
public class SynchronizedTest3 implements Runnable{
static SynchronizedTest3 st = new SynchronizedTest3();

  public static void main(String[] args) throws Exception{
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("run over");
}

  @Override
public void run(){
method();
}

  public synchronized void method(){
System.out.println("開始執行:" + Thread.currentThread().getName());
try {
// 模擬執行內容
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("執行結束:" + Thread.currentThread().getName());
}
}

  結果:

  開始執行:Thread-0
執行結束:Thread-0
開始執行:Thread-1
執行結束:Thread-1
run over

2、類鎖

  概念:Java類可能有多個對象,但只有一個Class對象

  本質:所謂的類鎖,不過是Class對象的鎖而已

  用法和效果:類鎖只能在同一時刻被一個對象擁有

  形式1:synchronized加載static方法上

  形式2:synchronized(*.class)代碼塊

  package cn.jsonshare.java.base.synchronizedtest;

  /**
* 類鎖:synchronized加載static方法上
*
* @author JSON
*/
public class SynchronizedTest4 implements Runnable{

  static SynchronizedTest4 st1 = new SynchronizedTest4();
static SynchronizedTest4 st2 = new SynchronizedTest4();

  public static void main(String[] args) throws Exception{
Thread t1 = new Thread(st1);
Thread t2 = new Thread(st2);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("run over");
}

  @Override
public void run(){
method();
}

  public static synchronized void method(){
System.out.println("開始執行:" + Thread.currentThread().getName());
try {
// 模擬執行內容
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("執行結束:" + Thread.currentThread().getName());
}
}

  package cn.jsonshare.java.base.synchronizedtest;

  /**
* 類鎖:synchronized(*.class)代碼塊
*
* @author JSON
*/
public class SynchronizedTest5 implements Runnable{
static SynchronizedTest4 st1 = new SynchronizedTest4();
static SynchronizedTest4 st2 = new SynchronizedTest4();

  public static void main(String[] args) throws Exception{
Thread t1 = new Thread(st1);
Thread t2 = new Thread(st2);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("run over");
}

  @Override
public void run(){
method();
}

  public void method(){
synchronized(SynchronizedTest5.class){
System.out.println("開始執行:" + Thread.currentThread().getName());
try {
// 模擬執行內容
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("執行結束:" + Thread.currentThread().getName());
}
}
}

  結果:

  開始執行:Thread-0
執行結束:Thread-0
開始執行:Thread-1
執行結束:Thread-1
run over
三、多線程訪問同步方法的7種情況

  

  兩個線程同時訪問一個對象的相同的synchronized方法

  

  兩個線程同時訪問兩個對象的相同的synchronized方法

  

  兩個線程同時訪問兩個對象的相同的static的synchronized方法

  

  兩個線程同時訪問同一對象的synchronized方法與非synchronized方法

  

  兩個線程訪問同一對象的不同的synchronized方法

  

  兩個線程同時訪問同一對象的static的synchronized方法與非static的synchronized方法

  

  方法拋出異常後,會釋放鎖嗎

  

  仔細看下面示例代碼結果輸出的結果,注意輸出時間間隔,來預測結論

  在公眾號程式設計師小樂回復「Java」,獲取Java面試題和答案驚喜禮包。

  場景1:

  package cn.jsonshare.java.base.synchronizedtest;

  /**
* 兩個線程同時訪問一個對象的相同的synchronized方法
*
* @author JSON
*/
public class SynchronizedScene1 implements Runnable{
static SynchronizedScene1 ss = new SynchronizedScene1();

  public static void main(String[] args) throws Exception{
Thread t1 = new Thread(ss);
Thread t2 = new Thread(ss);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("run over");
}

  @Override
public void run(){
method();
}

  public synchronized void method(){
System.out.println("開始執行:" + Thread.currentThread().getName());
try {
// 模擬執行內容
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("執行結束:" + Thread.currentThread().getName());
}
}

  場景2:

  package cn.jsonshare.java.base.synchronizedtest;

  /**
* 兩個線程同時訪問兩個對象的相同的synchronized方法
*
* @author JSON
*/
public class SynchronizedScene2 implements Runnable{
static SynchronizedScene2 ss1 = new SynchronizedScene2();
static SynchronizedScene2 ss2 = new SynchronizedScene2();

  public static void main(String[] args) throws Exception{
Thread t1 = new Thread(ss1);
Thread t2 = new Thread(ss2);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("run over");
}

  @Override
public void run(){
method();
}

  public synchronized void method(){
System.out.println("開始執行:" + Thread.currentThread().getName());
try {
// 模擬執行內容
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("執行結束:" + Thread.currentThread().getName());
}
}

  場景3:

  package cn.jsonshare.java.base.synchronizedtest;

  /**
* 兩個線程同時訪問兩個對象的相同的static的synchronized方法
*
* @author JSON
*/
public class SynchronizedScene3 implements Runnable{
static SynchronizedScene3 ss1 = new SynchronizedScene3();
static SynchronizedScene3 ss2 = new SynchronizedScene3();

  public static void main(String[] args) throws Exception{
Thread t1 = new Thread(ss1);
Thread t2 = new Thread(ss2);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("run over");
}

  @Override
public void run(){
method();
}

  public synchronized static void method(){
System.out.println("開始執行:" + Thread.currentThread().getName());
try {
// 模擬執行內容
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("執行結束:" + Thread.currentThread().getName());
}
}

  場景4:

  package cn.jsonshare.java.base.synchronizedtest;

  /**
* 兩個線程同時訪問同一對象的synchronized方法與非synchronized方法
*
* @author JSON
*/
public class SynchronizedScene4 implements Runnable{
static SynchronizedScene4 ss1 = new SynchronizedScene4();

  public static void main(String[] args) throws Exception{
Thread t1 = new Thread(ss1);
Thread t2 = new Thread(ss1);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("run over");
}

  @Override
public void run(){
// 模擬兩個線程同時訪問 synchronized方法與非synchronized方法
if(Thread.currentThread().getName().equals("Thread-0")){
method1();
}else{
method2();
}
}

  public void method1(){
System.out.println("method1開始執行:" + Thread.currentThread().getName());
try {
// 模擬執行內容
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("method1執行結束:" + Thread.currentThread().getName());
}

  public synchronized void method2(){
System.out.println("method2開始執行:" + Thread.currentThread().getName());
try {
// 模擬執行內容
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("method2執行結束:" + Thread.currentThread().getName());
}
}

  場景5:

  package cn.jsonshare.java.base.synchronizedtest;

  /**
* 兩個線程訪問同一對象的不同的synchronized方法
*
* @author JSON
*/
public class SynchronizedScene5 implements Runnable{
static SynchronizedScene5 ss1 = new SynchronizedScene5();

  public static void main(String[] args) throws Exception{
Thread t1 = new Thread(ss1);
Thread t2 = new Thread(ss1);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("run over");
}

  @Override
public void run(){
// 模擬兩個線程同時訪問不同的synchronized方法
if(Thread.currentThread().getName().equals("Thread-0")){
method1();
}else{
method2();
}
}

  public synchronized void method1(){
System.out.println("method1開始執行:" + Thread.currentThread().getName());
try {
// 模擬執行內容
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("method1執行結束:" + Thread.currentThread().getName());
}

  public synchronized void method2(){
System.out.println("method2開始執行:" + Thread.currentThread().getName());
try {
// 模擬執行內容
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("method2執行結束:" + Thread.currentThread().getName());
}
}

  場景6:

  package cn.jsonshare.java.base.synchronizedtest;

  /**
* 兩個線程同時訪問同一對象的static的synchronized方法與非static的synchronized方法
*
* @author JSON
*/
public class SynchronizedScene6 implements Runnable{
static SynchronizedScene6 ss1 = new SynchronizedScene6();

  public static void main(String[] args) throws Exception{
Thread t1 = new Thread(ss1);
Thread t2 = new Thread(ss1);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("run over");
}

  @Override
public void run(){
// 模擬兩個線程同時訪問static的synchronized方法與非static的synchronized方法
if(Thread.currentThread().getName().equals("Thread-0")){
method1();
}else{
method2();
}
}

  public static synchronized void method1(){
System.out.println("method1開始執行:" + Thread.currentThread().getName());
try {
// 模擬執行內容
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("method1執行結束:" + Thread.currentThread().getName());
}

  public synchronized void method2(){
System.out.println("method2開始執行:" + Thread.currentThread().getName());
try {
// 模擬執行內容
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("method2執行結束:" + Thread.currentThread().getName());
}
}

  場景7:

  package cn.jsonshare.java.base.synchronizedtest;

  /**
* 方法拋出異常後,會釋放鎖嗎
*
* @author JSON
*/
public class SynchronizedScene7 implements Runnable{
static SynchronizedScene7 ss1 = new SynchronizedScene7();

  public static void main(String[] args) throws Exception{
Thread t1 = new Thread(ss1);
Thread t2 = new Thread(ss1);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("run over");
}

  @Override
public void run(){
method1();
}

  public synchronized void method1(){
System.out.println("method1開始執行:" + Thread.currentThread().getName());
try {
// 模擬執行內容
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
// 模擬異常
throw new RuntimeException();
//System.out.println("method1執行結束:" + Thread.currentThread().getName());
}
}
總結:

  1、兩個線程同時訪問一個對象的相同的synchronized方法

  同一實例擁有同一把鎖,其他線程必然等待,順序執行

  在公眾號程式設計師小樂回復「offer」,獲取算法面試題和答案驚喜禮包。

  2、兩個線程同時訪問兩個對象的相同的synchronized方法

  不同的實例擁有的鎖是不同的,所以不影響,並行執行

  3、兩個線程同時訪問兩個對象的相同的static的synchronized方法

  靜態同步方法,是類鎖,所有實例是同一把鎖,其他線程必然等待,順序執行

  4、兩個線程同時訪問同一對象的synchronized方法與非synchronized方法

  非synchronized方法不受影響,並行執行

  5、兩個線程訪問同一對象的不同的synchronized方法

  同一實例擁有同一把鎖,所以順序執行(說明:鎖的是this對象==同一把鎖)

  6、兩個線程同時訪問同一對象的static的synchronized方法與非static的synchronized方法

  static同步方法是類鎖,非static是對象鎖,原理上是不同的鎖,所以不受影響,並行執行

  7、方法拋出異常後,會釋放鎖嗎

  會自動釋放鎖,這裡區別Lock,Lock需要顯示的釋放鎖

  3個核心思想:

  

  一把鎖只能同時被一個線程獲取,沒有拿到鎖的線程必須等待(對應1、5的情景)

  

  每個實例都對應有自己的一把鎖,不同的實例之間互不影響;例外:鎖對象是*.class以及synchronized被static修飾的時候,所有對象共用同一把鎖(對應2、3、4、6情景)

  

  無論是方法正常執行完畢還是方法拋出異常,都會釋放鎖(對應7情景)

  

補充:

  問題:目前進入到被synchronized修飾的方法,這個方法裡邊調用了非synchronized方法,是線程安全的嗎?

  package cn.jsonshare.java.base.synchronizedtest;

  /**
* 目前進入到被synchronized修飾的方法,這個方法裡邊調用了非synchronized方法,是線程安全的嗎?
*
* @author JSON
*/
public class SynchronizedScene8 {
public static void main(String[] args) {
new Thread(() -> {
method1();
}).start();

  new Thread(() -> {
method1();
}).start();
}

  public static synchronized void method1() {
method2();
}

  private static void method2() {
System.out.println(Thread.currentThread().getName() + "進入非Synchronized方法");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}

  System.out.println(Thread.currentThread().getName() + "結束非Synchronized方法");
}
}

  結論:這樣是線程安全的

  四、性質 1、可重入

  指的是同一線程的外層函數獲取鎖之後,內層函數可以直接再次獲取該鎖

  Java典型的可重入鎖:synchronized、ReentrantLock

  好處:避免死鎖,提升封裝性

  粒度:線程而非調用

  

  情況1:證明同一方法是可重入的

  

  情況2:證明可重入不要求是同一方法

  

  情況3:證明可重入不要求是同一類中的

  

2、不可中斷

  一旦這個鎖被別的線程獲取了,如果我現在想獲得,我只能選擇等待或者阻塞,直到別的線程釋放這個鎖,如果別的線程永遠不釋放鎖,那麼我只能永遠的等待下去。

  相比之下,Lock類可以擁有中斷的能力,第一點:如果我覺得我等待的時間太長了,有權中斷現在已經獲取到鎖的線程執行;第二點:如果我覺得我等待的時間太長了不想再等了,也可以退出。

  五、原理 1、加解鎖原理(現象、時機、深入JVM看字節碼)

  現象:每一個類的實例對應一把鎖,每一個synchronized方法都必須首先獲得調用該方法的類的實例的鎖,方能執行,否則就會阻塞,方法執行完成或者拋出異常,鎖被釋放,被阻塞線程才能獲取到該鎖,執行。

  獲取和釋放鎖的時機:內置鎖或監視器鎖

  package cn.jsonshare.java.base.synchronizedtest;

  import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

  /**
* method1 等價於 method2
*
* @author JSON
* @date 2019-08-29
*/
public class SynchronizedToLock1 {
Lock lock = new ReentrantLock();

  public synchronized void method1(){
System.out.println("執行method1");
}

  public void method2(){
lock.lock();
try {
System.out.println("執行method2");
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}

  public static void main(String[] args) {
SynchronizedToLock1 sl = new SynchronizedToLock1();

  // method1 等價於 method2
sl.method1();
sl.method2();
}
}

  深入JVM看字節碼:

  ...
monitorenter指令
...
monitorexit指令
...

2、可重入原理(加鎖次數計數器)

  JVM負責跟蹤對象被加鎖的次數

  線程第一次給對象加鎖的時候,計數變為1,每當這個相同的線程在此對象上再次獲得鎖時,計數會遞增

  每當任務離開時,計數遞減,當計數為0的時候,鎖被完全釋放

  3、可見性原理(內存模型)

  Java內存模型

  

  線程A向線程B發送數據的過程(JMM控制)

  

  synchronized關鍵字實現可見性:

  

被synchronized修飾,那麼執行完成後,對對象所做的任何修改都要在釋放鎖之前,都要從線程內存寫入到主內存,所以主內存中的數據是最新的。

六、缺陷

1、效率低

  1)、鎖的釋放情況少(線程執行完成或者異常情況釋放)

  2)、試圖獲得鎖時不能設定超時(只能等待)

  3)、不能中斷一個正在試圖獲得鎖的線程(不能中斷)

  2、不夠靈活

  加鎖和釋放的時機比較單一,每個鎖僅有單一的條件(某個對象),可能是不夠的

  比如:讀寫鎖更靈活

  3、無法預判是否成功獲取到鎖 七、常見問題 1、synchronized關鍵字注意點:

  

  鎖對象不能為空

  

  作用域不宜過大

  

  避免死鎖

  

2、如何選擇Lock和synchronized關鍵字?

  總結建議(優先避免出錯的原則):

  

  如果可以的話,儘量優先使用java.util.concurrent各種類(不需要考慮同步工作,不容易出錯)

  

  優先使用synchronized,這樣可以減少編寫代碼的量,從而可以減少出錯率

  

  若用到Lock或Condition獨有的特性,才使用Lock或Condition

  

八、總結

  一句話總結synchronized:

  JVM會自動通過使用monitor來加鎖和解鎖,保證了同一時刻只有一個線程可以執行指定的代碼,從而保證線程安全,同時具有可重入和不可中斷的特性。

  

版權申明:內容來源網絡,版權歸原創者所有。除非無法確認,我們都會標明作者及出處,如有侵權煩請告知,我們會立即刪除並表示歉意。謝謝!

  

相關焦點

  • Java之戳中痛點之 synchronized 深度解析
    2、地位3、不控制並發的影響測試:兩個線程同時a++,猜一下結果package cn.jsonshare.java.base.synchronizedtest;/** * 不使用synchronized,兩個線程同時a++ * * @author JSON */public class SynchronizedTest1
  • JAVA中synchronized與static synchronized 的區別
    那麼static synchronized恰好就是要控制類的所有實例的訪問了,static synchronized是限制線程同時訪問jvm中該類的所有實例同時訪問對應的代碼快。個人分析也就是synchronized 與static synchronized 相當於兩幫派,各自管各自,相互之間就無約束了,可以被同時訪問。目前還不是分清楚java內部設計synchronzied是怎麼樣實現的。
  • Java synchronized 詳解
    參與構建火車票業務系統的底層技術支持體系,個人對並發編程、分布式系統等技術點感興趣。前言記得剛剛學習Java的時候,遇到多線程情況首先想到的就是synchronized。相對於當時的我們來說,synchronized是那麼的神奇而強大,同時它也成為我們解決多線程情況百試不爽的良藥。
  • Java開發中synchronized的定義及用法
    synchronizedsynchronized是java中用於同步的關鍵字,其典型的作用域如下所示.用於保證test1函數中的被synchronized大括號包裹的代碼同步執行.synchronized作用的對象為SynchronizedExample1的對象實例,例如main函數中的example1以及example2.
  • Java多線程synchronized
    在Java中,提供了兩種方式來實現同步互斥訪問:synchronized和Lock。本文主要講述synchronized的使用方法,Lock的使用方法在下一篇博文中講述。synchronized同步方法synchronized是Java語言的關鍵字,當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執行該段代碼。
  • Java的synchronized 能防止指令重排序嗎?
    「二胖」:好的,我叫二胖,我來自長沙,今年25歲,從事java開發快3年了,現在在XX公司XX事業部擔任高級「java」開發工程師,主要負責XX系統。。。。。「面試官」:好的,我看你簡歷上寫著熟練掌握並發編程你能跟我說說並發編程裡面你都知道哪些關鍵字。
  • Java 重寫(Override)與重載(Overload)的區別
    在使用Overload方法時要注意以下3點:1、不能通過拋出的異常、訪問權限、返回類型進行重載;2、對於繼承來說,如果某一方法在父類中的訪問權限是priavte,那麼就不能在子類中進行重載。即使定義,也不會達到重載的效果,只是定義一個新方法。
  • JAVA多線程 集合同步
    詞彙解析如何以線程安全的方式使用Java List?A.)中,否則有可能拋出ConcurrentModificationException異常,如下(3)例子中所示用法。原文連結:http://www.javamadesoeasy.com/2015/12/how-to-synchronize-arraylist-in-java-to.html幾乎所有的集合非線程安全的?
  • Java基礎之Socket篇
    SmileThe Royal Concept - SmileJava基礎之Socket篇Hello,大家好!我是老醜,今天分享的是一些關於Socket的知識。本文閱讀預計15分鐘左右。目錄-什麼是Socket?
  • java 基礎 之 集合 Map
    //: containers/Maps.java// Things you can do with Maps.import java.util.concurrent.*;import java.util.*;import net.mindview.util.
  • JVM之用Java解析class文件
    java解析class文件/前言:身為一個Java程式設計師,怎麼能不了解JVM呢,倘若想學習JVM,那就又必須要了解Class文件,Class之於虛擬機,就如魚之於水,虛擬機因為Class而有了生命。作者講解的很詳細,每個過程都分為了一章,其中一部分就是講解如何解析Class文件。這本書不太厚,很快就讀完了,讀完後,收穫頗豐。但是紙上得來終覺淺,絕知此事要躬行,我便嘗試著自己解析Class文件。go語言雖然很優秀,但是終究不熟練,尤其是不太習慣其把類型放在變量之後的語法,還是老老實實用java吧。
  • Java反射,泛型在Json中的運用
    最近項目中遇到了Json數據自動獲取的功能,不然令人想起java的反射,已經很長時間沒複習java了正好一塊連java的這一塊內容一起過一遍。java中的反射無疑就相當於java開發者的春天,在眾多的框架中也能看到它的身影,可以在運行時檢查類,接口、變量和方法等信息,可以實例化調用方法以及設置變量值等。本文主要以代碼的形式直接將反射,泛型的運用展現出來。java中的反射首先新建一個基礎類Author。
  • 1分鐘讀懂java中的volatile關鍵字
    本文將以儘量簡潔的方式介紹java中的volatile關鍵字。如果覺得寫的不錯,記得,如果寫的不好歡迎批評指正,讓我們一起進步!1.volatile簡介先來看volatile這個單詞的本義:說簡單點,volatile就是表示某人或某物是不穩定的、易變的。
  • 「轉載」java架構之路(多線程)synchronized詳解以及鎖的膨脹升級...
    synchronized是jvm內部的一把隱式鎖,一切的加鎖和解鎖過程是由jvm虛擬機來控制的,不需要我們認為的幹預,我們大致從了解鎖,到synchronized的使用,到鎖的膨脹升級過程三個角度來說一下synchronized。
  • Java的單例模式
    new Instance()確實非原子操作,但是synchronized不正是為了保證非原子操作的線程安全才用的麼?同一時刻,能進到synchronized代碼塊裡的不應該只有一個線程麼,怎麼會有線程A沒執行完new Instance()指令,線程B就進到了synchronized代碼塊裡的情況呢?
  • Java並發編程之支持並發的list集合你知道嗎
    Java並發編程之-list集合的並發.我們都知道Java集合類中的arrayList是線程不安全的。那麼怎麼證明是線程不安全的呢?怎麼解決在並發環境下使用安全的list集合類呢?本篇是《凱哥(凱哥Java:kagejava)並發編程學習》系列之《並發集合系列》教程的第一篇:本文主要內容:怎麼證明arrayList不是線程安全的?怎麼解決這個問題?以及遇到問題解決的四個步驟及從源碼來分析作者思路。一:怎麼證明arrayList在並發情況下是線程不安全的呢?
  • Java內存分配和String類型的深度解析
    一、引題在java語言的所有數據類型中,String類型是比較特殊的一種類型,同時也是面試的時候經常被問到的一個知識點,本文結合java內存分配深度分析關於String的許多令人迷惑的問題。下面是本文將要涉及到的一些問題,如果讀者對這些問題都了如指掌,則可忽略此文。1、java內存具體指哪塊內存?這塊內存區域為什麼要進行劃分?是如何劃分的?
  • java集合容器之Stack
    從名字看他就是一個stack,因此具有數據結構中棧的一般特性(後進先出),平時用起來相對較多一點,但是也是非常簡單。這篇文章我們將從源碼的角度來分析一下Stack。OK,開始今天的文章。一、認識StackStack繼承自Vector。底層是通過數組實現的。
  • 使用Lock鎖:java多線程安全問題解決方案之Lock鎖
    今天我們來學習一下Lock鎖,它是java 1.5之後出現的接口 java.util.concurrent.locks.Lock接口Lock實現提供了比使用 synchronized 方法和語句可獲得的更廣泛的鎖定操作,就來釋放鎖和獲取鎖來說,在使用synchronized 方法的時候,我們並不知道什麼時候獲取到了鎖,什麼時候釋放了鎖,而Lock接口不一樣,他提供了專門的獲取鎖和釋放鎖的方法。
  • 死磕 java所有集合之終結篇
    點擊下面連結可以直接到相應的章節查看:死磕 java集合之HashMap源碼分析死磕 java集合之LinkedHashMap源碼分析死磕 java集合之WeakHashMap源碼分析死磕 java集合之TreeMap源碼分析(一)死磕 java集合之TreeMap源碼分析(二)死磕 java集合之TreeMap