1. 程式人生 > >java執行緒 - synchronized詳解

java執行緒 - synchronized詳解

synchronized : 代表同步的修飾符

目錄

1.特性:

2.互斥性demo:

3.重入性講解


1.特性:

  1. 互斥性(排他性) : 同一時刻,只允許一個執行緒進行訪問,會一直等待執行緒釋放鎖,容易造成死鎖。
  2. 重入性: 程式或者子程式可以在任意時刻被中斷然後系統排程另一段程式碼,這段程式碼又呼叫了該子程式,並不會出錯。 也                 就是說,一個執行緒執行了某個程式,是可以再次進入該程式並執行。

        內建鎖

:類借用synchronized是實現了一個內建性,我覺得更像是類的特性,只不過是類借用了這個修飾符來實現的內建                          性。所有類都可以用自身物件建立一個內建鎖。

2.互斥性demo:

一 . synchronized修飾普通方法:針對的是物件的某一例項。(並不影響物件的其他例項)


package com.test.concurrencyThread;

public class Test implements Runnable {

    public synchronized void test() {
        try {
            System.out.println(Thread.currentThread().getName());
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

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

    public static void main(String[] args) {
        Runnable runnable = new Test();
        Runnable runnable1 = new Test();
        Thread thread = new Thread(runnable);
        thread.start();
        Thread thread1 = new Thread(runnable1);
        thread1.start();
    }
}


 


程式輸出:

Thread-0
Thread-1
(兩者幾乎同時輸出)


package com.test.concurrencyThread;

public class Test implements Runnable {

    public synchronized void test() {
        try {
            System.out.println(Thread.currentThread().getName());
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

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

    public static void main(String[] args) {
        Runnable runnable = new Test();
        Thread thread = new Thread(runnable);
        thread.start();
        Thread thread1 = new Thread(runnable);
        thread1.start();
    }
}



再看這第二個demo,由兩個執行緒啟動同一個Test的例項,輸出的結果沒變,只是在輸出thread-0之後過了5秒,才輸出Thread-1。

Thread-0
Thread-1

由此可見,synchronized修飾普通方法:針對的是物件的某一例項。(並不影響物件的其他例項)。


二. synchronized修飾靜態方法:針對的是整個類。

package com.test.concurrencyThread;

public class Test implements Runnable {

    public synchronized static void test1() {
        try {
            System.out.println(Thread.currentThread().getName());
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

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

    public static void main(String[] args) {
        Runnable runnable = new Test();
        Runnable runnable1 = new Test();
        Thread thread = new Thread(runnable);
        thread.start();
        Thread thread1 = new Thread(runnable1);
        thread1.start();
    }
}



 

 接下來synchronized修飾靜態方法,無論是建立一個例項還是兩個例項,都是先輸出一個,之後過了5秒,再輸出第二個。

Thread-0
Thread-1

由此可見,synchronized修飾靜態方法:針對的是整個類


三. synchronized修飾程式碼塊:針對的是synchronized修飾的物件,(不影響synchronized修飾的其他物件)


package com.test.concurrencyThread;

public class Test implements Runnable {

    private final Object object = new Object();

    private void test1() {
        synchronized (object) {
            try {
                System.out.println(Thread.currentThread().getName());
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

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

    public static void main(String[] args) {
        Runnable runnable = new Test();
        Thread thread = new Thread(runnable);
        thread.start();
        Thread thread1 = new Thread(runnable);
        thread1.start();
    }
}


 


建立一個Test例項,由兩個執行緒執行。結果也是先輸出一個,過五秒之後,又輸出第二個。

Thread-0
Thread-1


package com.test.concurrencyThread;

public class Test implements Runnable {

    private final Object object = new Object();

    private void test1() {
        synchronized (object) {
            try {
                System.out.println(Thread.currentThread().getName());
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

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

    public static void main(String[] args) {
        Runnable runnable = new Test();
        Runnable runnable1 = new Test();
        Thread thread = new Thread(runnable);
        thread.start();
        Thread thread1 = new Thread(runnable1);
        thread1.start();
    }
}



Thread-0
Thread-1
結果幾乎同時輸出。由此可見,synchronized修飾程式碼塊:針對的是synchronized修飾的物件,(不影響其他synchronized修飾的物件)。


3.重入性講解

當一個執行緒請求一個由其他執行緒持有的物件鎖時,該執行緒會阻塞。當執行緒請求自己持有的物件鎖時,如果該執行緒是重入鎖,請求就會成功,否則阻塞。

我們回來看synchronized,synchronized擁有強制原子性的內部鎖機制,是一個可重入鎖。因此,在一個執行緒使用synchronized方法時呼叫該物件另一個synchronized方法,即一個執行緒得到一個物件鎖後再次請求該物件鎖,是永遠可以拿到鎖的

在Java內部,同一個執行緒呼叫自己類中其他synchronized方法/塊時不會阻礙該執行緒的執行,同一個執行緒對同一個物件鎖是可重入的,同一個執行緒可以獲取同一把鎖多次,也就是可以多次重入。原因是Java中執行緒獲得物件鎖的操作是以執行緒為單位的,而不是以呼叫為單位的。   

------此段引用 https://www.cnblogs.com/cielosun/p/6684775.html