Java 中物件鎖和類鎖的區別?
阿新 • • 發佈:2020-12-08
一 物件鎖和類鎖的關係
/* * 物件鎖和【類鎖】 全域性鎖的關係? 物件鎖是用於物件例項方法,或者一個物件例項上的 this 類鎖是用於類的靜態方法或者一個類的class物件上的。 Ag.class 我們知道,類的物件例項可以有很多個,但是每個類只有一個class物件, 所以不同物件例項的物件鎖是互不干擾的,但是每個類只有一個類鎖。 */
物件鎖, 不同物件。
public class SynchrDemo { public static void main(String[] args) { Thread1 thread1= new Thread1(); Thread1 thread2 = new Thread1(); thread1.start(); thread2.start(); } } class Ag{ public void show(){ // this 是當前物件的例項,由於新建兩個物件,不是同一物件。所以這裡是鎖不住的。 程式碼快的方式,比修飾在方法上更細化控制。 synchronized (this) { for (int i = 0; i < 4; i++) { System.out.println(Thread.currentThread().getName()+ " i=" + i); } } } } class Thread1 extends Thread{ @Override public void run() { //這裡是新建物件 主方法中new了兩個thread,就是new了兩個Ag物件 Ag ag = new Ag(); ag.show(); } }
關鍵字修飾方法
public class SynchrDemo { public static void main(String[] args) { Thread1 thread1= new Thread1(); Thread1 thread2 = new Thread1(); thread1.start(); thread2.start(); } } class Ag{ // 這次修飾的是方法,範圍比程式碼塊要大,意味著在這個區域內,鎖生效的時候,都是在阻塞,其他執行緒的等待時間就會增加。 // 這次實驗的非同一物件,所以這裡的鎖是不起作用的。 public synchronized void show(){ for (int i = 0; i < 4; i++) { System.out.println(Thread.currentThread().getName() + " i=" + i); } } } class Thread1 extends Thread{ @Override public void run() { //這裡是新建物件 主方法中new了兩個thread,就是new了兩個Ag物件 Ag ag = new Ag(); ag.show(); } }
二 物件鎖 同一物件
package com.aaa.threaddemo; /* * 一 Java中的關鍵字 synchronized 是啥? * synchronized是Java提供的一個併發控制的關鍵字。 * * 用法:同步方法 和 同步程式碼塊。 * 可以修飾方法 也可以 修飾程式碼塊。 * * 作用: 被synchronized修飾的程式碼塊及方法,在同一時間,只能被單個執行緒訪問。【保證執行緒安全】 1 修飾方法和程式碼塊有什麼不同? 二者的結果是一樣的 修飾方法時,作用域是整個方法,控制的範圍大。 synchronized 程式碼塊 可控制具體的作用域,更精準控制提高效率。 減少阻塞帶來的時間問題。 2 同步鎖的給誰用的? 同步鎖基於物件,只要鎖的來源一致,即可達到同步的作用。 所以,但物件不一樣,則不能達到同步效果。 3 synchronized修飾方法,程式碼塊,鎖未釋放,此時,其他執行緒呼叫同一物件的其他被synchronized修飾的方法,程式碼塊,會如何? 當執行緒 A 呼叫某物件的synchronized 方法 或者 synchronized 程式碼塊時,若同步鎖未釋放, 其他執行緒呼叫同一物件的其他 synchronized 方法 或者 synchronized 程式碼塊時將被阻塞,直至執行緒 A 釋放該物件的同步鎖。(注意:重點是其他) 4 呼叫非synchronized方法 ,程式碼快呢? 當執行緒 A 呼叫某物件的synchronized 方法 或者 synchronized 程式碼塊時,無論同步鎖是否釋放, 其他執行緒呼叫同一物件的其他 非 synchronized 方法 或者 非 synchronized 程式碼塊時可立即呼叫。 5 全域性鎖如何實現? 全域性鎖: 鎖住整個 Class,而非某個物件或例項。1-4都是例項鎖 實現: 靜態 synchronized 方法 static 宣告的方法為全域性方法,與物件例項化無關, 所以 static synchronized 方法為全域性同步方法,與物件例項化無關。 6 synchronized 具體 Class 的程式碼塊? synchronized (Ag.class) 獲得的同步鎖是全域性的, static synchronized 獲得的同步鎖也是全域性的,同一個鎖,所以達到同步效果。 7 物件鎖和【類鎖】 全域性鎖的關係? 物件鎖是用於物件例項方法,或者一個物件例項上的 this 類鎖是用於類的靜態方法或者一個類的class物件上的。 Ag.class 我們知道,類的物件例項可以有很多個,但是每個類只有一個class物件, 所以不同物件例項的物件鎖是互不干擾的,但是每個類只有一個類鎖。 * * */ /* * 物件鎖和【類鎖】 全域性鎖的關係? 物件鎖是用於物件例項方法,或者一個物件例項上的 this 類鎖是用於類的靜態方法或者一個類的class物件上的。 Ag.class 我們知道,類的物件例項可以有很多個,但是每個類只有一個class物件, 所以不同物件例項的物件鎖是互不干擾的,但是每個類只有一個類鎖。 */ public class SynchrDemo { public static void main(String[] args) { // 改造後,可以確保是同一物件 驗證 synchronized 是否生效 Ag ag = new Ag(); Thread1 thread1 = new Thread1(ag); Thread1 thread2 = new Thread1(ag); thread1.start(); thread2.start(); } } class Ag{ // 這次修飾的是方法,範圍比程式碼塊要大,意味著在這個區域內,鎖生效的時候,都是在阻塞,其他執行緒的等待時間就會增加。 // 這次實驗的同一物件,所以這裡的鎖是起作用的。 public synchronized void show(){ for (int i = 0; i < 4; i++) { System.out.println(Thread.currentThread().getName() + " i=" + i); } } } /* * 改造一些 物件的生成,確保在Thread1 中獲得的是同一物件 */ class Thread1 extends Thread{ private Ag mag; public Thread1(Ag ag) { mag = ag; } @Override public void run() { mag.show(); } }
驗證程式碼快的方式?
public class SynchrDemo { public static void main(String[] args) { // 改造後,可以確保是同一物件 驗證 synchronized 是否生效 Ag ag = new Ag(); Thread1 thread1 = new Thread1(ag); Thread1 thread2 = new Thread1(ag); thread1.start(); thread2.start(); } } class Ag{ // 這次修飾的是方法,範圍比程式碼塊要大,意味著在這個區域內,鎖生效的時候,都是在阻塞,其他執行緒的等待時間就會增加。 // 這次實驗的同一物件,所以這裡的鎖是起作用的。 public void show(){ synchronized (this) { for (int i = 0; i < 4; i++) { System.out.println(Thread.currentThread().getName() + " i=" + i); } // this 就是當前的物件,我們現在獲得就是同一物件 System.out.println(this); } } } /* * 改造一些 物件的生成,確保在Thread1 中獲得的是同一物件 */ class Thread1 extends Thread{ private Ag mag; public Thread1(Ag ag) { mag = ag; } @Override public void run() { mag.show(); } }
三 類鎖? 非同一物件
/* * * 類鎖,全域性鎖如何實現? 全域性鎖: 鎖住整個 Class,而非某個物件或例項 實現: 1 在靜態方法上用 synchronized 關鍵字修飾 2 在程式碼塊上使用 類名.class static 宣告的方法為全域性方法,與物件例項化無關, 所以 static synchronized 方法為全域性同步方法,與物件例項化無關。 */ public class SynchrDemo { public static void main(String[] args) { //非同一物件 Thread2 thread1 = new Thread2(); Thread2 thread2 = new Thread2(); thread1.start(); thread2.start(); } } class Ag{ public void show(){ // 使用 synchronized() 方法,將鎖控制在程式碼快上。 synchronized (Ag.class) { for (int i = 0; i < 4; i++) { System.out.println(Thread.currentThread().getName() + " i=" + i); } // this 就是當前的物件,我們現在獲得就是非同一物件 System.out.println(this); } } } class Thread2 extends Thread{ @Override public void run() { Ag ag = new Ag(); ag.show(); } }
測試 關鍵字修飾 static 方法
public class SynchrDemo { public static void main(String[] args) { //非同一物件 Thread2 thread1 = new Thread2(); Thread2 thread2 = new Thread2(); thread1.start(); thread2.start(); } } class Ag{ // 靜態的方法 被synchronized 修飾後, 鎖住的是 類。 public static synchronized void show(){ for (int i = 0; i < 4; i++) { System.out.println(Thread.currentThread().getName() + " i=" + i); } } } class Thread2 extends Thread{ @Override public void run() { Ag ag = new Ag(); ag.show(); } }