java併發編程——線程同步

sysynchronized關鍵字能夠修飾方法、代碼塊,但不能修飾構造器、成員變量等。java

當sysynchronized關鍵字同來修飾方法和代碼塊時,可以保證同一時刻最多隻有一個線程執行該段代碼或方法。防止當有兩個線程併發修改同一個文件時可能會形成異常。編程

同步代碼塊語法:安全

synchronized(obj){
        ...
        //此處代碼是同步代碼塊
    }
複製代碼

意思爲:當線程要執行如下代碼塊以前,必須先得到對obj的鎖。bash

當兩個併發線程訪問同一個對象object中的synchronized(this)同步代碼塊時,一個時間內只能有一個線程獲得執行。另外一個線程必須等待當前線程執行完代碼塊之後才能執行該代碼塊。

然而,另外一個當一個線程訪問object的一個synchronized(this)代碼塊時,另外一個線程仍然能夠訪問該object中的非synchronized(this)同步代碼塊,可是其餘線程對object中其餘全部的synchronized(this)同步代碼塊的訪問將被阻塞併發

示例:ide

public class Thread1 {

    public void synchronize() {
        synchronized (this) {
            System.out.println("I am the synchronized part:");
            for (int i=0; i<3; i++) {
                System.out.println(Thread.currentThread().getName()+":"+(i+1));
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
            System.out.println("the synchronized part is over");
        }
    }

    public void synchronize2() {
        synchronized (this) {
            System.out.println("I am the synchronized part 2:");
            for (int i=0; i<3; i++) {
                System.out.println(Thread.currentThread().getName()+":"+(i+1));
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
            System.out.println("the synchronized part 2 is over");
        }
    }

    public void nonSynchronize() {
        System.out.println("non-synchronized part:");
        for (int i=0; i<3; i++) {
            System.out.println(Thread.currentThread().getName()+":"+(i+1));
            try {
                Thread.sleep(500);
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        System.out.println("the non-synchronized part is over");
    }

    public static void main(String[] args) {
        final Thread1 thread1 = new Thread1();

    //啓動線程,線程一、2和3分別用了不一樣的表達式
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                thread1.synchronize();
            }
        });
        Thread t2 = new Thread(() -> thread1.synchronize2());
        Thread t3 = new Thread(thread1::nonSynchronize);
        t1.start();
        t2.start();
        t3.start();
    }
}複製代碼

輸出結果:工具


從輸出結果能夠看出:線程0執行的是第一個同步代碼塊,線程2執行的是非同步代碼塊,線程0和2同時執行,二者互不干擾。線程1執行的是第二個同步代碼塊,由於線程0先得到對該對象的鎖定,因此線程1即便執行代碼塊跟線程0不同,也被阻塞,必須等線程1執行完同步代碼塊,釋放鎖,線程1才能繼續執行。this

同步方法示例

public class Thread1 {

    private synchronized void synchronize() {
        System.out.println("I am the synchronized method part:");
        for (int i=0; i<3; i++) {
            System.out.println(Thread.currentThread().getName()+":"+(i+1));
            try {
                Thread.sleep(500);
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        System.out.println("the synchronized method part is over");
    }

    private synchronized void synchronize2() {
        System.out.println("I am the synchronized method part 2:");
        for (int i=0; i<3; i++) {
            System.out.println(Thread.currentThread().getName()+":"+(i+1));
            try {
                Thread.sleep(500);
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        System.out.println("the synchronized method part 2 is over");
    }

    private  void nonSynchronize() {
        System.out.println("non-synchronized method part:");
        for (int i=0; i<3; i++) {
            System.out.println(Thread.currentThread().getName()+":"+(i+1));
            try {
                Thread.sleep(500);
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        System.out.println("the non-synchronized method part is over");
    }

    public static void main(String[] args) {
        final Thread1 thread1 = new Thread1();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                thread1.synchronize();
            }
        });
        Thread t2 = new Thread(() -> thread1.synchronize2());
        Thread t3 = new Thread(thread1::nonSynchronize);
        t1.start();
        t2.start();
        t3.start();
    }
}複製代碼

輸出結果跟同步代碼塊同樣:spa


同步鎖

Lock 是控制多個線程對共享資源進行訪問的工具。每次只能有一個線程對Lock對象加鎖,線程開始訪問共享資源以前應先得到Lock對象。.net

在實現線程安全的控制中,比較經常使用的是ReentrantLock。

class X {
    private final ReentrantLock lock = new ReentrantLock();
    //定義須要保證線程安全的方法
    public void m() {
        //加鎖
        lock.lock();
        try {
            //method body
        } finally { //使用finally來保證釋放鎖
            lock.unlock();
        }
    }
}複製代碼


參考資料:java加鎖與同步方法

瘋狂java講義(第三版)

Java編程思想(第4版)

相關文章
相關標籤/搜索