java synchronized

關於synchronized的初步使用,你們看拙做

關於synchronized

便可


不過今天,有個朋友問我,若是用synchronized修飾一個類的成員變量會怎麼樣?

我們看下面的代碼

package thread;public class ThreadTestffd { private Integer a = 0; private Integer b = 0; public static void main(String[] args) {  ThreadTestffd test = new ThreadTestffd();  test.A();  test.B(); } public void A() {  new Thread(new Runnable() {   @Override   public void run() {    System.out.println("A線程準備");    synchronized (a) {     System.out.println("A線程開始");     for (int i = 0; i < 10; i++) {      System.out.println("a" + i);      try {       Thread.sleep(500);      } catch (InterruptedException e) {       e.printStackTrace();      }     }    }   }  }).start(); } public void B() {  new Thread(new Runnable() {   @Override   public void run() {    System.out.println("B線程準備");    synchronized (b) {     System.out.println("B線程開始");     for (int i = 0; i < 10; i++) {      System.out.println("b" + i);      try {       Thread.sleep(500);      } catch (InterruptedException e) {       e.printStackTrace();      }     }    }   }  }).start(); }}

    1

最後的結果是先等a方法運行完以後,纔打印出來b線程開始,固然"b線程準備"很早就打印了

這說明什麼,我猜想就是:

用synchronized修飾成員變量,就直接限制了這個對象實例,synchronized(成員變量)就等於synchronized(this)


那若是有兩個對象呢?

就像我把代碼改爲:

 private  Integer a = 0; private  Integer b = 0; public static void main(String[] args) {  ThreadTestffd test = new ThreadTestffd();  test.A();  ThreadTestffd test2 = new ThreadTestffd();  test2.B(); }

    1

那結果應該是什麼樣的?

應該是交錯打印的麼?

應該是的,畢竟兩個對象麼

可是結果不是,結果是先打印a而後打印b

臥槽?日了狗了!

我腦子突然想到一個問題,要不咱換一個成員變量?

 private Person a=new Person(); private Person b=new Person(); public static void main(String[] args) {  ThreadTestffd test = new ThreadTestffd();  test.A();  test.B(); }

    1

最後的結果是交替打印,Person就是一個簡單的pojo類

我靠什麼狀況?integer和pseron的結果不同

後來,我突然想到了integer是有緩存的,以下:

    public static Integer valueOf(int i) {        assert IntegerCache.high >= 127;        if (i >= IntegerCache.low && i <= IntegerCache.high)            return IntegerCache.cache[i + (-IntegerCache.low)];        return new Integer(i);    }

    1

在-128到127直接的都是一個對象

也就是說最開始的代碼,雖然一個鎖a一個鎖b,可是鎖的都是同一個對象

後面的,把ab改爲了person,就交替打印了,由於a和b壓根就不是同一個對象

因此上面的結論:

用synchronized修飾成員變量,就直接限制了這個對象實例,synchronized(成員變量)就等於synchronized(this)

也是不對的

synchronized(成員變量A)與synchronized(成員變量B)是沒有關係的,他們互補干擾

其實也對,既然用鎖,那就一個對象麼,一個a一個b什麼鬼?

夥計說:我就測試測試....


其實這篇博客的名字應該叫談談integer的緩存的

緩存

========================================================多線程

這裏主要涉及到類對象(static方法),對象方法(非static方法)ide

咱們知道,當synchronized修飾一個static方法時,多線程下,獲取的是類鎖(即Class自己,注意:不是實例);測試

當synchronized修飾一個非static方法時,多線程下,獲取的是對象鎖(即類的實例對象)this

因此,當synchronized修飾一個static方法時,建立線程不論是new JoinThread()仍是new Thread(new JoinThread()),在run方法中執行inc()方法都是同步的;atom

相反,當synchronized修飾一個非static方法時,若是用new JoinThread()仍是new Thread(new JoinThread())方式建立線程,就沒法保證同步操做,由於這時線程

inc()是屬於對象方法,每一個線程都執有一個獨立的對象實例new JoinThread(),因此多線程下執行inc()方法並不會產生互斥,也不會有同步操做。對象

 

另外若是考慮到變動的原子操做,可以使用atomic包下面的包裝對象,這些對象都是對volatile修飾變量的一種延伸,可保證變量的原子操做而不用去同步方法或繼承

代碼塊是否同步同步

 

==============================

必須注意的地方:一、某個對象實例內,synchronized aMethod(){}關鍵字能夠防止多個線程訪問對象的synchronized方法(若是一個對象有多個synchronized方法,只要一個線程訪問了其中的一個synchronized方法,其它線程不能同時訪問這個對象中任何一個synchronized方法)。這時,不一樣的對象實例的synchronized方法是不相干擾的。也就是說,其它線程照樣能夠同時訪問相同類的另外一個對象實例中的synchronized方法.二、synchronized關鍵字是不能繼承的,也就是說,基類的方法synchronized f(){} 在繼承類中並不自動是synchronized f(){},而是變成了f(){}。繼承類須要你顯式的指定它的某個方法爲synchronized方法;三、然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另外一個線程仍然能夠訪問該object中的非synchronized(this)同步代碼塊。四、尤爲關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其餘線程對object中全部其它synchronized(this)同步代碼塊的訪問將被阻塞。也就是說,當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就得到了這個object的對象鎖。結果,其它線程對該object對象全部同步代碼部分的訪問都被暫時阻塞。

相關文章
相關標籤/搜索