8鎖現象 八鎖->就是關於鎖的八個問題 鎖是什麼,如何判斷鎖的是誰 對象、class模板 深刻理解鎖 鎖的東西無外乎就兩樣:1、同步方法的調用者,2、Class模板。 同一個鎖中,只有當前線程資源釋放後才會被下一個線程所接手。 同步方法的調用者是兩個不同的實例時,互不相關。 靜態同步方法(stati ...
8鎖現象
八鎖->就是關於鎖的八個問題
鎖是什麼,如何判斷鎖的是誰
對象、class模板
深刻理解鎖
鎖的東西無外乎就兩樣:1、同步方法的調用者,2、Class模板。
同一個鎖中,只有當前線程資源釋放後才會被下一個線程所接手。
同步方法的調用者是兩個不同的實例時,互不相關。
靜態同步方法(static)鎖的是整個Class模板,和同步方法的調用者也不是同一個鎖;切Class模板在Java程式中唯一。
代碼示例
1、淺淺理解鎖的作用
同一把鎖中根據執行先後釋放資源,保證一個資源的使用順序
package org.example.phone;
import java.util.concurrent.TimeUnit;
public class Test1 {
public static void main(String[] args) {
// 標準情況下,列印順序為 1、發簡訊,2、打電話
// 給sendMsg內部延遲四秒執行,執行順序依舊是 1、發簡訊,2、打電話
// 可知,並非是我們所想的,A線程在前面就先執行,而是鎖的機制導致了這種情況
// phone1只創建了一個對象,所以這個對象的鎖只有一把,誰先拿到就是誰先執行
// 鎖的對象是該方法的調用者,即phone1
Phone1 phone1 = new Phone1();
new Thread(()->{
phone1.sendMsg();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(()->{
phone1.call();
},"B").start();
}
}
class Phone1{
// synchronized鎖的對象是方法的調用者,Phone1只new了一個對象,所以鎖的是new出來的整個對象
public synchronized void sendMsg(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("發簡訊");
}
public synchronized void call(){
System.out.println("打電話");
}
}
2、區分鎖的對象
不同的實例使用的鎖並非同一把,所以也無法同時鎖定某個固定的資源、無法對同一資源進行有順序的操作
package org.example.phone;
import java.util.concurrent.TimeUnit;
public class Test3 {
public static void main(String[] args) {
// 標準情況下,列印順序為 1、發簡訊,2、打電話
// 給sendMsg內部延遲四秒執行,執行順序依舊是 1、發簡訊,2、打電話
// 可知,並非是我們所想的,A線程在前面就先執行,而是鎖的機制導致了這種情況
// phone1只創建了一個對象,所以這個對象的鎖只有一把,誰先拿到就是誰先執行
// 鎖的對象是該方法的調用者,即phone1
// 調用兩個不同對象的方法,鎖的是兩個不同的對象,此時先出現打電話,說明不同對象之間的鎖互不影響
Phone3 phone3_1 = new Phone3();
Phone3 phone3_2 = new Phone3();
new Thread(()->{
phone3_1.sendMsg();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(()->{
phone3_2.call();
},"B").start();
}
}
class Phone3{
// synchronized鎖的對象是方法的調用者,Phone1只new了一個對象,所以鎖的是new出來的整個對象
public synchronized void sendMsg(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("發簡訊");
}
public synchronized void call(){
System.out.println("打電話");
}
// 當在資源類中添加了一個普通方法後,先輸出hello
// 沒有鎖,不是同步方法,不受鎖的影響
public void hello(){
System.out.println("Hello");
}
}
3、瞭解鎖的參與者
只有同步方法參與鎖,普通方法依舊按照java執行順序執行
package org.example.phone;
import java.util.concurrent.TimeUnit;
public class Test2 {
public static void main(String[] args) {
// 標準情況下,列印順序為 1、發簡訊,2、打電話
// 給sendMsg內部延遲四秒執行,執行順序依舊是 1、發簡訊,2、打電話
// 可知,並非是我們所想的,A線程在前面就先執行,而是鎖的機制導致了這種情況
// phone1只創建了一個對象,所以這個對象的鎖只有一把,誰先拿到就是誰先執行
// 鎖的對象是該方法的調用者,即phone1
Phone2 phone2 = new Phone2();
new Thread(()->{
phone2.sendMsg();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(()->{
phone2.hello();
},"B").start();
}
}
class Phone2{
// synchronized鎖的對象是方法的調用者,Phone1只new了一個對象,所以鎖的是new出來的整個對象
public synchronized void sendMsg(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("發簡訊");
}
public synchronized void call(){
System.out.println("打電話");
}
// 當在資源類中添加了一個普通方法後,先輸出hello
// 沒有鎖,不是同步方法,不受鎖的影響
public void hello(){
System.out.println("Hello");
}
}
4、明白鎖能鎖誰
鎖只能鎖兩個東西,一個是同步方法的調用者,一個是整個Class模板(全局唯一),一旦使用static創建靜態同步方法,那麼該方法的鎖鎖的就是全局唯一的Class模板,並且在反射時就已經被創建了
package org.example.phone;
import java.util.concurrent.TimeUnit;
public class Test4 {
public static void main(String[] args) {
// 兩個對象的Class類模板只有一個;static,鎖的是Class
Phone4 phone4_1 = new Phone4();
Phone4 phone4_2 = new Phone4();
new Thread(()->{
phone4_1.sendMsg();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(()->{
phone4_2.call();
},"B").start();
}
}
class Phone4{
// synchronized鎖的對象是方法的調用者
// 註:增加了static靜態方法 此時調用該方法的就變成了Phone4的反射對象,全局唯一
// 此時鎖的就是Class模板了,即不管你有幾個調用者,都在同一個鎖
// static方法類一載入就有了!鎖的是Class
public static synchronized void sendMsg(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("發簡訊");
}
public static synchronized void call(){
System.out.println("打電話");
}
}
5、深入理解鎖的是誰
靜態同步方法和普通同步方法在一起使用時,鎖的並非同一對象,所以列印順序也時按java的執行順序來,並不存在鎖定資源的情況
package org.example.phone;
import java.util.concurrent.TimeUnit;
/*
* 1、一個靜態同步方法,一個普通同步方法,先列印發簡訊還是打電話
* 兩個方法一個鎖的是Class模板,一個鎖的是調用者,鎖的不是同一對象,所以延遲四秒的靜態同步方法後列印,延遲一秒的普通同步方法先列印
*
* */
public class Test5 {
public static void main(String[] args) {
Phone5 phone5_1 = new Phone5();
// Phone5 phone5_2 = new Phone5();
new Thread(()->{
phone5_1.sendMsg();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(()->{
phone5_1.call();
},"B").start();
}
}
class Phone5{
// 鎖的是Class模板
public static synchronized void sendMsg(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("發簡訊");
}
// 鎖的是調用者
public synchronized void call(){
System.out.println("打電話");
}
}