相關免費學習推薦:java基礎教學
8鎖定問題示範
1.標準訪問
/*手机类可以发邮件和发短信*/class Phone{ public synchronized void sendEmail() throws Exception{ System.out.println("***sendEmail"); } public synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { phone.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
標準訪問,先列印郵件還是簡訊.
不一定誰先被列印。取決於CPU的執行情況.激活他們的是main線程,後面誰先被調度,不知道。
為了確保效果,我們在A和B的程式碼之間加thread.sleep(100)。此時,可以確保A先被列印。
解釋:
只要一個資源類別裡面,不管它有多少個同步方法,只要一個執行緒先存取了資源類別裡面的任何一個同步方法,那麼它鎖的不是這個方法,鎖的是該方法所在的整個資源類別。也就是說,鎖的是對象。它鎖的不是目前的方法。
也就是說,這些synchoronized的方法都屬於同一個資源類別裡面,而鎖的是整個資源類別。
2.在郵件方法中暫停4秒,請問先列印郵件還是簡訊
/*手机类可以发邮件和发短信*/class Phone{ public synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { phone.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
先列印郵件。同步方法取得的phone物件鎖定,sleep不會釋放鎖定。到了時間會立即執行。所以先列印郵件方法
解釋:
它與問題1類似。
只要一個資源類別裡面,不管它有多少個同步方法,只要一個執行緒先存取了資源類別裡面的任何一個同步方法,那麼它鎖的不是這個方法,鎖的是這個方法所在的整個資源類別。也就是說,鎖的是對象。它鎖的不是目前的方法。
舉個例子:我和班長要用同一個手機打電話,我一定要等班長打完電話才能接著打。班長用的過程中停網了一段時間,那我也只能等班長打完。
3.新增普通sayHello方法,請問先列印郵件還是hello
#先列印hello
/*手机类可以发邮件和发短信*/class Phone{ public synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); } public void sayHello(){ System.out.println("***sayHello"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { //phone.sendSMS(); phone.sayHello(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
#解釋:加上普通方法後發現和同步鎖定無關。因此它無需等待同步鎖釋放。
這裡可以舉個例子。班長用它的手機要打電話。而我要向班長借手機充電線,這兩個不互斥,因此可以在班長打電話完之前就借走充電線。
4.兩部手機,請問先印郵件還是簡訊
/*手机类可以发邮件和发短信*/class Phone{ public synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); } public void sayHello(){ System.out.println("***sayHello"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); Phone phone2=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { //phone.sendSMS(); //phone.sayHello(); phone2.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
解釋:這裡可以舉個例子,班長用它的手機法郵件。我用我自己的手機打電話。那麼誰先誰後就沒有關係。
5.兩個靜態同步方法,同一部手機,請問先印郵件還是簡訊
/*手机类可以发邮件和发短信*/class Phone{ public static synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public static synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); } public void sayHello(){ System.out.println("***sayHello"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); Phone phone2=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { phone.sendSMS(); //phone.sayHello(); //phone2.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
6.兩個靜態同步方法,兩部手機,請問先印郵件還是簡訊
/*手机类可以发邮件和发短信*/class Phone{ public static synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public static synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); } public void sayHello(){ System.out.println("***sayHello"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); Phone phone2=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { //phone.sendSMS(); //phone.sayHello(); phone2.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
/*手机类可以发邮件和发短信*/class Phone{ public static synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); } public void sayHello(){ System.out.println("***sayHello"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); Phone phone2=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { phone.sendSMS(); //phone.sayHello(); //phone2.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
一個靜態,一個普通。鎖的是同一支手機。靜態方法鎖的是Class.相當於我們鎖了一個校門,一個是普通同步方法,鎖的是目前物件。比如教師普通的們。鎖的對像不一樣。就不衝突
######8.1個靜態同步方法,1個普通同步方法,兩部手機,請問先印郵件還是簡訊######/*手机类可以发邮件和发短信*/class Phone{ public static synchronized void sendEmail() throws Exception{ TimeUnit.SECONDS.sleep(4); //表示暂停4秒,它是一个枚举类型 System.out.println("***sendEmail"); } public synchronized void sendSMS() throws Exception{ System.out.println("***sendSMS"); } public void sayHello(){ System.out.println("***sayHello"); }}public class Lock8Demo { public static void main(String[] args) throws InterruptedException { //创建一个资源类 Phone phone=new Phone(); Phone phone2=new Phone(); new Thread(()->{ try { phone.sendEmail(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"A").start(); Thread.sleep(100); new Thread(()->{ try { //phone.sendSMS(); //phone.sayHello(); phone2.sendSMS(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } },"B").start(); }}
1.一個物件裡面如果有多個syncrhonized方法,某一時刻內,只要有一個線程去調用其中的一個synchronized方法了,其他的線程都只能等待,換句話說,某一刻內,只能有唯一一個執行緒去存取這些synchronized方法。
鎖的是目前物件this,被鎖定後,其他的執行緒都無法進入到目前物件的其他synchronized方法
加個普通方法後發現和同步鎖定無關。
換乘兩個物件後,不是同一把鎖了,情況立刻改變。
都換成靜態同步方法後,情況立刻改變
所有的非靜態同步方法用的都是同一把鎖------實例物件本身
2.synchronized實現同步的基礎:java中的每個物件都可以作為鎖。
具體表現為以下3種形式:
當一個行程試圖存取同步程式碼區塊時,它首先必須得到鎖,退出或拋出例外必須釋放鎖。
也就是說一個實例物件的非靜態同步方法取得鎖定後,該實例物件的其他非靜態同步方法必須等待取得鎖定的方法釋放鎖定後才能取得鎖定。可是別的實例物件的非靜態同步方法因為跟該實例物件的非靜態同步方法用的是不同的鎖,所以無需等待該實例物件已取得鎖的非靜態同步方法釋放鎖就可以取得自己的鎖。
所有的靜態同步方法用的也是同一把鎖-----類別物件本身。
這兩把鎖是兩個不同的對象,所以靜態同步方法與非靜態同步方法之間是不會有競態條件的。 (問題78)。即一個鎖class,一個鎖this,兩者不衝突。
但是一旦一個靜態同步方法取得鎖定後,其他的靜態同步方法都必須等待該方法釋放鎖定後才能取得鎖定。而不管是同一個實例物件的靜態方法之間,或是不同的實例物件的靜態同步方法之間,只要它們同一個類別的實例物件。 (問題56)
以上是Java介紹八鎖問題帶你徹底理解物件鎖和類別鎖的詳細內容。更多資訊請關注PHP中文網其他相關文章!