synchronized和lock鎖(一)

1.聲明synchronized方法的方式,這個稱之爲方法鎖或者對象鎖。

synchronized void f(){/*....*/}
synchronized void g(){/*....*/}

    全部的對象都自動含有單一的鎖(也稱爲監視器,前面閱讀Thread源碼有提到監視器)。當在對象上調用任意synchronized方法時,此對象都被加鎖,這時該對象上的其餘synchronized方法只有等到前一個方法調用完畢釋放了鎖以後才能被調用。對於前面的方法,若是某個任務對對象調用了f(),對於同一個對象而言,只有等到f()調用結束並釋放了鎖以後,其餘任務才能調用f()或者g()。因此,對於某個特定的對象來講,其全部的synchronized方法共享同一個鎖,這能夠被用來防止多個任務同時訪問被編碼對象內存。java

    一個任務能夠屢次得到對象鎖,也就是鎖可重入。是指,一個方法在同一個對象上調用了第二個方法,後者又調用了同一個對象上的另一個方法,就是發生鎖的重入。JVM負責跟蹤對象被枷鎖的次數。若是一個對象被解鎖也就說鎖被徹底釋放,其計數變爲0。在任務第一次給對象加鎖時,計數變爲1。每當這個相同的任務在這個對象上得到鎖的時候,計數都會遞增。顯然,只有先得到了鎖的任務才能容許繼續得到鎖。每當任務離開一個synchronized方法,計數遞減,當計數爲0的時候,鎖被徹底釋放,此時別的任務就能夠繼續使用此資源。併發

2.類鎖,能夠看作特殊的對象鎖,鎖的是類對象

    針對每一個類,也有一個鎖,做爲Class對象的一部分,因此synchronized static方法能夠在類的範圍內防止對static數據的併發訪問。ide

3.顯式使用Lock對象

    基本上,當你使用關鍵字synchronized關鍵字時,須要的代碼量更少,而且用戶出現錯誤的機率更低,所以一般只有解決特殊任務時纔會使用到現實的Lock對象。好比,用synchronized不能嘗試獲取鎖而且最終會獲取鎖失敗,或者嘗試着獲取鎖等待一段時間,這些須要concurrent類庫this

abstract class IntGenerator{
    private volatile boolean canceled = false;
    public abstract int next();
    public void cancel(){this.canceled =true;}
    public boolean isCanceled(){return this.canceled;}
}

class EvenChecker implements Runnable{

    private IntGenerator generator;
    private final int id;
    public EvenChecker(IntGenerator g,int ident){
        generator = g;
        id = ident;
    }

    public void run() {
        while (!generator.isCanceled()){
            int val = generator.next();
            if(val%2 != 0){
                System.out.println(val + " not even!");
                generator.cancel();
            }
        }
    }

    public static void test(IntGenerator gp,int count){
        System.out.println("Press Contrl-C to exit");
        ExecutorService exec = Executors.newCachedThreadPool();
        for(int i=0;i<count;i++){
            exec.execute(new EvenChecker(gp,i));
        }
        exec.shutdown();

    }

    public static void test(IntGenerator gp){
        test(gp,10);
    }
}

class SynchronizedEvenGenerator extends IntGenerator{
    private int currentVlaue = 0;

    public synchronized int next() {
        ++currentVlaue;
        //當不使用synchronized修飾next方法時,調用該方法能夠促使線程同步調用異常發生
        //Thread.yield();
        //一樣說明一個問題Thread。yield即使是讓出cpu可是並無釋放鎖
        ++currentVlaue;
        return currentVlaue;
    }
}

class MutexEvenGenerator extends IntGenerator{
    private int currentVlaue = 0;
    private Lock lock = new ReentrantLock();

    public int next() {
        lock.lock();
        try{
            ++currentVlaue;
            //當不使用synchronized修飾next方法時,調用該方法能夠促使線程同步調用異常發生
            Thread.yield();
            //一樣說明一個問題Thread。yield即使是讓出cpu可是並無釋放鎖
            ++currentVlaue;
            return currentVlaue;
        }finally {
            lock.unlock();
        }

    }
}

public class NesttyMain implements Serializable{

    public static void main(String[] args){
//        EvenChecker.test(new SynchronizedEvenGenerator());
        EvenChecker.test(new MutexEvenGenerator());
    }

}
相關文章
相關標籤/搜索