首頁 > Java > Java基礎 > 主體

Java介紹八鎖問題帶你徹底理解物件鎖和類別鎖

coldplay.xixi
發布: 2021-02-09 18:06:23
轉載
3421 人瀏覽過

Java介紹八鎖問題帶你徹底理解物件鎖和類別鎖

相關免費學習推薦: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();
	}}
登入後複製

Java介紹八鎖問題帶你徹底理解物件鎖和類別鎖
標準訪問,先列印郵件還是簡訊.
不一定誰先被列印。取決於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();
	}}
登入後複製

Java介紹八鎖問題帶你徹底理解物件鎖和類別鎖

Java介紹八鎖問題帶你徹底理解物件鎖和類別鎖

#解釋:加上普通方法後發現和同步鎖定無關。因此它無需等待同步鎖釋放。

這裡可以舉個例子。班長用它的手機要打電話。而我要向班長借手機充電線,這兩個不互斥,因此可以在班長打電話完之前就借走充電線。

Java介紹八鎖問題帶你徹底理解物件鎖和類別鎖
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();
	}}
登入後複製

解釋:這裡可以舉個例子,班長用它的手機法郵件。我用我自己的手機打電話。那麼誰先誰後就沒有關係。 Java介紹八鎖問題帶你徹底理解物件鎖和類別鎖

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一起分析

Java介紹八鎖問題帶你徹底理解物件鎖和類別鎖
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();
	}}
登入後複製
## 解析: static屬於一個類別。也就說,他不屬於當前對象this的一個獨立的個體。而是屬於全域的class。這就要考慮物件鎖和全域鎖的差別。全域鎖即類鎖。此時不管是一個phone或多個phone都來自於同一個類別Phone類別。現在不管你鎖到了哪個對象,我都要等他釋放完了這個鎖才能使用。

Java介紹八鎖問題帶你徹底理解物件鎖和類別鎖

7.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();
	}}
登入後複製

一個靜態,一個普通。鎖的是同一支手機。靜態方法鎖的是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();
	}}
登入後複製
######### ###解釋:這個跟上面是一樣的。 #########8鎖定理論解釋######

1.一個物件裡面如果有多個syncrhonized方法,某一時刻內,只要有一個線程去調用其中的一個synchronized方法了,其他的線程都只能等待,換句話說,某一刻內,只能有唯一一個執行緒去存取這些synchronized方法。
鎖的是目前物件this,被鎖定後,其他的執行緒都無法進入到目前物件的其他synchronized方法

加個普通方法後發現和同步鎖定無關。
換乘兩個物件後,不是同一把鎖了,情況立刻改變。
都換成靜態同步方法後,情況立刻改變
所有的非靜態同步方法用的都是同一把鎖------實例物件本身

2.synchronized實現同步的基礎:java中的每個物件都可以作為鎖。
具體表現為以下3種形式:

  1. 對於普通同步方法,鎖是目前實例物件
  2. 對於同步方法區塊,鎖定是synchronized括號裡面配置的物件。
    例如在方法裡寫
    synchronized(this){
    }
  3. #對於靜態同步方法,鎖定是目前類別的Class物件。

當一個行程試圖存取同步程式碼區塊時,它首先必須得到鎖,退出或拋出例外必須釋放鎖。
也就是說一個實例物件的非靜態同步方法取得鎖定後,該實例物件的其他非靜態同步方法必須等待取得鎖定的方法釋放鎖定後才能取得鎖定。可是別的實例物件的非靜態同步方法因為跟該實例物件的非靜態同步方法用的是不同的鎖,所以無需等待該實例物件已取得鎖的非靜態同步方法釋放鎖就可以取得自己的鎖。

所有的靜態同步方法用的也是同一把鎖-----類別物件本身。
這兩把鎖是兩個不同的對象,所以靜態同步方法與非靜態同步方法之間是不會有競態條件的。 (問題78)。即一個鎖class,一個鎖this,兩者不衝突。
但是一旦一個靜態同步方法取得鎖定後,其他的靜態同步方法都必須等待該方法釋放鎖定後才能取得鎖定。而不管是同一個實例物件的靜態方法之間,或是不同的實例物件的靜態同步方法之間,只要它們同一個類別的實例物件。 (問題56)

以上是Java介紹八鎖問題帶你徹底理解物件鎖和類別鎖的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:csdn.net
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板