Java之戳中痛點之 synchronized 深度解析

2021-03-02 Java專欄

第一時間閱讀精彩文章!

2、☞ 《Java面試手冊》.PDF    點擊查看

作者: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


Java知音公眾號內回復「面試題聚合」,送你一份面試題寶典三、多線程訪問同步方法的7種情況

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

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

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

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

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

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

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

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

場景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());
    }
}


Java知音公眾號內回復「面試題聚合」,送你一份面試題寶典總結:

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

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

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來加鎖和解鎖,保證了同一時刻只有一個線程可以執行指定的代碼,從而保證線程安全,同時具有可重入和不可中斷的特性。

獲取方式:

1、公眾號後臺回復「手冊」

2、掃描下方二維碼,回復「手冊」

相關焦點

  • Java之戳中痛點之 synchronized 深度解析|java|override|author|...
    package cn.jsonshare.java.base.synchronizedtest;  /*** 目前進入到被synchronized修飾的方法,這個方法裡邊調用了非synchronized方法,是線程安全的嗎?
  • JAVA中synchronized與static synchronized 的區別
    那麼static synchronized恰好就是要控制類的所有實例的訪問了,static synchronized是限制線程同時訪問jvm中該類的所有實例同時訪問對應的代碼快。個人分析也就是synchronized 與static synchronized 相當於兩幫派,各自管各自,相互之間就無約束了,可以被同時訪問。目前還不是分清楚java內部設計synchronzied是怎麼樣實現的。
  • Java開發中synchronized的定義及用法
    synchronizedsynchronized是java中用於同步的關鍵字,其典型的作用域如下所示.用於保證test1函數中的被synchronized大括號包裹的代碼同步執行.synchronized作用的對象為SynchronizedExample1的對象實例,例如main函數中的example1以及example2.
  • Java synchronized 詳解
    參與構建火車票業務系統的底層技術支持體系,個人對並發編程、分布式系統等技術點感興趣。前言記得剛剛學習Java的時候,遇到多線程情況首先想到的就是synchronized。相對於當時的我們來說,synchronized是那麼的神奇而強大,同時它也成為我們解決多線程情況百試不爽的良藥。
  • Java多線程synchronized
    在Java中,提供了兩種方式來實現同步互斥訪問:synchronized和Lock。本文主要講述synchronized的使用方法,Lock的使用方法在下一篇博文中講述。synchronized同步方法synchronized是Java語言的關鍵字,當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執行該段代碼。
  • Java的synchronized 能防止指令重排序嗎?
    「二胖」:好的,我叫二胖,我來自長沙,今年25歲,從事java開發快3年了,現在在XX公司XX事業部擔任高級「java」開發工程師,主要負責XX系統。。。。。「面試官」:好的,我看你簡歷上寫著熟練掌握並發編程你能跟我說說並發編程裡面你都知道哪些關鍵字。
  • Java並發編程:synchronized
    今天我們就來一起討論下線程安全問題,以及Java中提供了什麼機制來解決線程安全問題。以下是本文的目錄大綱:一.什麼時候會出現線程安全問題?二.如何解決線程安全問題?三.synchronized同步方法或者同步塊若有不正之處,請多多諒解並歡迎批評指正。一.什麼時候會出現線程安全問題?
  • 「轉載」java架構之路(多線程)synchronized詳解以及鎖的膨脹升級...
    synchronized是jvm內部的一把隱式鎖,一切的加鎖和解鎖過程是由jvm虛擬機來控制的,不需要我們認為的幹預,我們大致從了解鎖,到synchronized的使用,到鎖的膨脹升級過程三個角度來說一下synchronized。
  • Java面試熱點:深入學習並發編程中的synchronized(後三章)
    當該線程被喚醒時,會從掛起的點繼續執行,通過 ObjectMonitor::TryLock 嘗試獲取鎖。CAS和volatile實現無鎖並發package com.itheima.demo05_cas; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicInteger; public class Demo01
  • Java面試熱點學習:深入並發編程中的synchronized(前三章)
    有序性演示jcstress是java並發壓測工具。代碼I_Result 是一個對象,有一個屬性 r1 用來保存結果,在多線程情況下可能出現幾種結果?運行測試:mvn clean install java -jar target/jcstress.jar小結程序代碼在執行過程中的先後順序,由於Java在編譯期以及運行期的優化,導致了代碼的執行順序未必就是開發者編寫代碼時的順序。
  • Java基礎之Socket篇
    SmileThe Royal Concept - SmileJava基礎之Socket篇Hello,大家好!我是老醜,今天分享的是一些關於Socket的知識。本文閱讀預計15分鐘左右。目錄-什麼是Socket?
  • 並發編程(一)| Volatile 與 Synchronized 深度解析
    在一個操作中,讀取了 inc 變量後,是不會再讀取的 inc 的,所以它的值還是之前讀的 10,它的下一步是自增操作。二、Synchronized 關鍵字的實現及定義2.1 定義synchronized 關鍵字解決的是多個線程之間訪問資源的同步性,synchronized 關鍵字可以保證被它修飾的方法或者代碼塊在任意時刻只能有一個線程執行。
  • 「從入門到放棄-Java」並發編程-鎖-synchronized
    簡介上篇【從入門到放棄-Java】並發編程-線程安全中,我們了解到,可以通過加鎖機制來保護共享對象,來實現線程安全。synchronized是java提供的一種內置的鎖機制。通過synchronized關鍵字同步代碼塊。
  • 【死磕Java並發】深入分析synchronized實現原理
    同步代碼塊:monitorenter指令插入到同步代碼塊的開始位置,monitorexit指令插入到同步代碼塊的結束位置,JVM需要保證每一個monitorenter都有一個monitorexit與之相對應。任何對象都有一個monitor與之相關聯,當且一個monitor被持有之後,他將處於鎖定狀態。
  • JVM之用Java解析class文件
    java解析class文件/前言:身為一個Java程式設計師,怎麼能不了解JVM呢,倘若想學習JVM,那就又必須要了解Class文件,Class之於虛擬機,就如魚之於水,虛擬機因為Class而有了生命。作者講解的很詳細,每個過程都分為了一章,其中一部分就是講解如何解析Class文件。這本書不太厚,很快就讀完了,讀完後,收穫頗豐。但是紙上得來終覺淺,絕知此事要躬行,我便嘗試著自己解析Class文件。go語言雖然很優秀,但是終究不熟練,尤其是不太習慣其把類型放在變量之後的語法,還是老老實實用java吧。
  • java 基礎 之 集合 Map
    //: containers/Maps.java// Things you can do with Maps.import java.util.concurrent.*;import java.util.*;import net.mindview.util.
  • JAVA多線程 集合同步
    詞彙解析如何以線程安全的方式使用Java List?A.)中,否則有可能拋出ConcurrentModificationException異常,如下(3)例子中所示用法。原文連結:http://www.javamadesoeasy.com/2015/12/how-to-synchronize-arraylist-in-java-to.html幾乎所有的集合非線程安全的?
  • Java內存分配和String類型的深度解析
    一、引題在java語言的所有數據類型中,String類型是比較特殊的一種類型,同時也是面試的時候經常被問到的一個知識點,本文結合java內存分配深度分析關於String的許多令人迷惑的問題。下面是本文將要涉及到的一些問題,如果讀者對這些問題都了如指掌,則可忽略此文。1、java內存具體指哪塊內存?這塊內存區域為什麼要進行劃分?是如何劃分的?
  • Java並發編程之支持並發的list集合你知道嗎
    Java並發編程之-list集合的並發.我們都知道Java集合類中的arrayList是線程不安全的。那麼怎麼證明是線程不安全的呢?怎麼解決在並發環境下使用安全的list集合類呢?本篇是《凱哥(凱哥Java:kagejava)並發編程學習》系列之《並發集合系列》教程的第一篇:本文主要內容:怎麼證明arrayList不是線程安全的?怎麼解決這個問題?以及遇到問題解決的四個步驟及從源碼來分析作者思路。一:怎麼證明arrayList在並發情況下是線程不安全的呢?
  • Java的synchronized的使用
    Java的synchronized的使用Java中的額synchronized關鍵字,大家應該都很熟悉了,多線程中確保線程安全。Java中每個對象都可以作為鎖。對於靜態同步方法,鎖的是當前類的Clas3、對於同步方法塊,鎖的是synchronized裡面的對象。