線程併發學習----線程阻塞(synchronized)

線程併發學習

線程併發學習—-核心概念(轉載)
線程併發學習—-線程阻塞(sleep、wait、notifyAll、notify、join)
線程併發學習—-線程阻塞(synchronized)
線程併發學習—-線程阻塞(lock)
線程併發學習—-Thread、Runnable、Callable
線程併發學習—-隊列(Queue)
spring學習—-線程池
java中一些鎖概念整理(轉載)

簡介

在併發編程中,我們需要處理兩個關鍵問題:線程之間如何通信及線程之間如何同步(這裏的線程是指併發執行的活動實體)。

通信是指線程之間以何種機制來交換信息。在命令式編程中,線程之間的通信機制有兩種:共享內存和消息傳遞。

Java的併發採用的是共享內存模型,Java線程之間的通信總是隱式進行,整個通信過程對程序員完全透明。在共享內存併發模型裏,同步是顯式進行的。程序員必須顯式指定某個方法或某段代碼需要在線程之間互斥執行。

線程安全是併發編程中的重要關注點,應該注意到的是,造成線程安全問題的主要誘因有兩點,

一是存在共享數據(也稱臨界資源),
二是存在多條線程共同操作共享數據。

在 Java 中synchronized 和 lock可以保證在同一個時刻,只有一個線程可以執行某個方法或者某個代碼塊

關鍵字 synchronized可以保證在同一個時刻,只有一個線程可以執行某個方法或者某個代碼塊(主要是對方法或者代碼塊中存在共享數據的操作),同時我們還應該注意到synchronized另外一個重要的作用,synchronized可保證一個線程的變化(主要是共享數據的變化)被其他線程所看到(保證可見性,完全可以替代Volatile功能),這點確實也是很重要的。

synchronized三種使用方式

  • 修飾實例方法
  • 修飾靜態方法
  • 修飾同步代碼塊

修飾實例方法

實例代碼

public class NormalFunctionSyncDemo {
   public static void main(String[] args) {
        NormalFunctionSyncDemo normalFunctionSyncDemo = new NormalFunctionSyncDemo();
        new Thread(new Runnable() {
            @Override
            public void run() {
                normalFunctionSyncDemo.getA();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                NormalFunctionSyncDemo normalFunctionSyncDemo2 = new NormalFunctionSyncDemo();
                normalFunctionSyncDemo2.getB();
            }
        }).start();
    }


    public synchronized void getA(){
        System.out.println("get A.....");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end A");
    }

    public synchronized void getB(){

        System.out.println("get B.....");
        System.out.println("end B");

    }
}

結果分析

使用同一個實例對象,會阻塞
get A…..
end A
get B…..
end B
使用不同實例對象,不會阻塞
get A…..
get B…..
end B
end A

修飾靜態方法

代碼示例

public class StaticFunctionSyncDemo {
    public static void main(String[] args) {

        new Thread(new Runnable() {
            @Override
            public void run() {
                StaticFunctionSyncDemo.getA();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                StaticFunctionSyncDemo staticFunctionSyncDemo = new StaticFunctionSyncDemo();
                staticFunctionSyncDemo.getB();
                StaticFunctionSyncDemo.getA();
            }
        }).start();
    }


    public static synchronized void getA(){
        System.out.println("get A.....");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end A");
    }

    public synchronized void getB(){
        System.out.println("get B.....");
        System.out.println("end B");
    }
}

結果分析

通類直接調用或創建新的示例調用getA方法都會阻塞,getB方法不會

get A…..
get B…..
end B
end A
get A…..
end A

修飾同步代碼塊

代碼示例

public class StaticBlockSyncDemo {
    public static void main(String[] args) {
        StaticBlockSyncDemo staticBlockSyncDemo = new StaticBlockSyncDemo();
        new Thread(new Runnable() {
            @Override
            public void run() {
                staticBlockSyncDemo.getA();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                StaticBlockSyncDemo staticBlockSyncDemo2 = new StaticBlockSyncDemo();
                staticBlockSyncDemo.getB();
            }
        }).start();
    }


    public void getA(){
        System.out.println("get A.....");
        try {
            synchronized (this) {
                System.out.println("Method A execute");
                Thread.sleep(3000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end A");
    }

    public  void getB(){
        System.out.println("get B.....");
        try {
            synchronized (this) {
                System.out.println("Method B execute");
                Thread.sleep(3000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end B");
    }
}

結果分析

結果與實例方法類似,通過monitor監視器鎖實現

monitor監視器鎖

public void getA();
    Code:
       0: getstatic     #11                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #12                 // String get A.....
       5: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: aload_0
       9: dup
      10: astore_1
      //通過javap命令可以看到獲取monitor鎖
      11: monitorenter
      12: getstatic     #11                 // Field java/lang/System.out:Ljava/io/PrintStream;
      15: ldc           #14                 // String Method A execute
      17: invokevirtual #13                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      20: ldc2_w        #15                 // long 3000l
      23: invokestatic  #17                 // Method java/lang/Thread.sleep:(J)V
      26: aload_1
      27: monitorexit

參考資料
http://blog.csdn.net/javazejian/article/details/72828483?locationNum=5&fps=1
http://www.cnblogs.com/paddix/p/5374810.html

發佈了52 篇原創文章 · 獲贊 7 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章