具體知識學習與
https://blog.csdn.net/yansuoo/article/details/51248281
https://www.jianshu.com/p/6586d9f3b515
下面是自己的理解+代碼:
一.前置知識:
java的對象鎖和類鎖:java的對象鎖和類鎖在鎖的概念上基本上和內置鎖是一致的,但是,兩個鎖實際是有很大的區別的,對象鎖是用於對象實例方法,或者一個對象實例上的,類鎖是用於類的靜態方法或者一個類的class對象上的。我們知道,類的對象實例可以有很多個,但是每個類只有一個class對象,所以不同對象實例的對象鎖是互不干擾的,但是每個類只有一個類鎖。但是有一點必須注意的是,其實類鎖只是一個概念上的東西,並不是真實存在的,它只是用來幫助我們理解鎖定實例方法和靜態方法的區別的
二.代碼理解
- synchronized(對象鎖):兩種;
-
synchronized(this){ //互斥代碼 } 或: private Object lock = new Object(); public void test1(){ synchronized(lock){ //互斥代碼 } }
這裏的this,指的是調用它的實例對象,即鎖就是這個這裏對象 ; 而lock鎖則是任意對象鎖(所有需要這個對象的鎖的方法都不能同時執行),有些許的不同(所有線程線程能共用該鎖)。
-
代碼:
Ticket t1=new Ticket(); Ticket t2=new Ticket(); Ticket t3=new Ticket(); t1.start(); t2.start(); t3.start(); //測試三個線程 class Ticket extends Thread{ private int num=100; //Object obj = new Object(); public void run() { while(true) { //synchronized (obj) synchronized (this) { if(num>0)System.out.println(Thread.currentThread().getName()+".."+num--); try { Thread.sleep(100); }catch (Exception e) {} } System.out.println(Thread.currentThread().getName()+":釋放"); } } }
此時線程1.2.0.交替執行,但注意下一次線程1.2.0像執行必須對應鎖釋放,換句話說這裏三個線程對象對應了三個鎖,只鎖自己,不能鎖別人,cpu可以切換其他線程執行,只要沒被鎖。 而代碼註釋的第二種結果是: 與上面同理,也是隻能鎖自己。是把當前這個對象的成員變量(object)當做鎖,其實三個線程對象有三個不同的object對象,因爲這個變量不共享。
-
tips:這樣加鎖的好處 (這是最常用的高併發場景下要鎖住某個方法所用的操作) :如果這時用synchronized來修飾代碼塊:synchronized(obj){obj.testsy();},那麼這個方法加鎖的對象是obj這個對象,跟執行這行代碼的對象沒有關係,當一個線程執行這個方法時,這對其他同步方法時沒有影響的,因爲他們持有的鎖都完全不一樣。
private Object lock = new Object(); public void test1(){ synchronized(lock){ //互斥代碼 } }
-
private static Object lock = new Object();
但如果任意對象鎖改爲靜態的,則可以實現互斥了,所有線程共享這個鎖(共享這個變量)。
-
synchronized(類鎖)
-
對於類鎖來說其實和對象鎖一樣只是爲了區別靜態方法和普通方法,對於多個線程,都是一把鎖,和第5點的情況一樣
synchronized(A.class){ //互斥代碼 }
tips:object.getClass()和A.class實際意義不同,並且對於前者來說,出現多態時,可能會有問題
-
每個線程執行都得等內閣唯一的一把鎖釋放。
三:一點解釋:
Thread.sleep():強制線程休眠未來*ms時間內不進入CPU進行競爭,進入阻塞狀態,給其他線程機會執行,但是,他不會釋放鎖;且 *毫秒過去之後,這時候也許另外一個線程正在使用CPU,那麼這時候操作系統是不會重新分配CPU的, 直到那個線程掛起或結束;況且,即使這個時候恰巧輪到操作系統進行CPU 分配,那麼當前線程也不一定就是總優先級最高的那個,CPU還是可能被其他線程搶佔去。也不一定會論到調度他。
線程獲得對象鎖的同時,也可以獲得該類鎖,即同時獲得兩個鎖,這是允許的。