關於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對象全部同步代碼部分的訪問都被暫時阻塞。