1. 程式人生 > >java使用synchronized加鎖區域的實驗踩坑

java使用synchronized加鎖區域的實驗踩坑

我們都知道,java中可以使用synchronized對方法,或者變數加鎖,那麼,當我們使用synchronized對方法加鎖,對變數加鎖,shnchronized結合static一起使用,兩個普通方法同時呼叫一個使用synchronized方法等等情況下,會出現什麼樣的效果呢?

結論:

這裡先把結論寫在開頭,下面的都是實驗過程,想直接看結論的可以不看下面的。

  1. 一個加鎖方法和一個未加鎖方法之間不會互相影響,因為第一個方法加了鎖,鎖住的只是方法域裡面的這一個方法,對其它的方法並不會影響,如果我們在一個執行緒中呼叫上鎖的方法,即使在這個執行緒裡呼叫了sleep方法,也只是sleep了當前的執行緒,對另一個執行緒沒有影響,即使是用的同一個物件。
  2. 如果兩個方法都使用了synchronized加鎖,這是對每個這個類的物件的兩個方法加鎖,當我們在兩個執行緒中使用同一物件執行這兩個加鎖方法,會受到鎖的影響,但是如果使用兩個這個類的物件執行,就不會受到影響
  3. 如果兩個方法都使用了synchronized static加鎖,鎖住的是這個類的靜態方法,也就是說這個類的所有例項物件執行這兩個方法的時候都會受到影響
  4. 通過兩個加鎖方法呼叫同一個普通方法和通過兩個普通方法呼叫同一個加鎖方法的效果一樣,都是對過程加了鎖

實驗過程:

1.在兩個執行緒中使用同一物件先呼叫加鎖方法再呼叫未加鎖方法

物件的類:

public class
Lab { public synchronized void fun1() { System.out.println("呼叫加鎖方法"); try { Thread.sleep(2000);//在方法中沉睡2秒,達到鎖住的效果 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("加鎖方法執行完畢"); } public void fun2() { System.out.println("呼叫未加鎖方法"); } }

主方法:

public class
Test { public static void main(String[] args) { Lab lab = new Lab(); new Thread(new Runnable() { public void run() { lab.fun1();//呼叫加鎖方法 } }).start(); new Thread(new Runnable() { public void run() { lab.fun2();//呼叫未加鎖方法 } }).start(); } }

執行結果:
在這裡插入圖片描述
可以看到,在兩個執行緒中使用同一物件先呼叫加鎖方法再呼叫未加鎖方法並不會造成第二個方法因為第一個方法鎖住而無法執行,兩個方法併發執行。

2.在兩個執行緒中使用同一物件呼叫同一方法

public class Lab {
	public synchronized void fun1()
	{
		System.out.println("呼叫加鎖方法");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("加鎖方法執行完畢");
	}
	public void fun2()
	{
		System.out.println("呼叫未加鎖方法");
	}
}

public class Test {
	public static void main(String[] args) {
		Lab lab1 = new Lab();
		new Thread(new Runnable() {
			public void run() {
				lab1.fun1();//呼叫加鎖方法
			}
		}).start();
		
		new Thread(new Runnable() {
			public void run() {
				lab1.fun1();//呼叫未加鎖方法
			}
		}).start();
	}
}

執行結果:
在等待兩秒鐘上一個加鎖方法執行完畢了之後才執行第二遍,證明加鎖成功。
在這裡插入圖片描述

3.在兩個執行緒中使用同一物件先呼叫靜態加鎖方法再呼叫未加鎖方法

public class Lab {
	public synchronized static void fun1()//改為靜態加鎖方法
	{
		System.out.println("呼叫加鎖方法");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("加鎖方法執行完畢");
	}
	public void fun2()
	{
		System.out.println("呼叫未加鎖方法");
	}
}
public class Test {
	public static void main(String[] args) {
		Lab lab = new Lab();
		new Thread(new Runnable() {
			public void run() {
				lab.fun1();//使用物件呼叫類的靜態加鎖方法
			}
		}).start();
		
		new Thread(new Runnable() {
			public void run() {
				lab.fun2();//呼叫未加鎖方法
			}
		}).start();
	}
}

執行結果:
在這裡插入圖片描述
我們使用了物件去呼叫靜態方法,結果可以看到並沒有鎖住
以上證明了一個方法加鎖另一個方法不加鎖在兩個執行緒中互不影響

4.在兩個執行緒中使用同一物件先呼叫一個加鎖方法再呼叫另一個加鎖方法

public class Lab {
	public synchronized void fun1()
	{
		System.out.println("呼叫加鎖方法");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("加鎖方法執行完畢");
	}
	public synchronized void fun2()
	{
		System.out.println("呼叫未加鎖方法");
	}
}
public class Test {
	public static void main(String[] args) {
		Lab lab1 = new Lab();
		new Thread(new Runnable() {
			public void run() {
				lab1.fun1();//呼叫加鎖方法
			}
		}).start();
		
		new Thread(new Runnable() {
			public void run() {
				lab1.fun2();//呼叫未加鎖方法
			}
		}).start();
	}
}

執行結果:輸出呼叫加鎖方法等了兩秒鐘後才出來後兩行輸出,加鎖成功
在這裡插入圖片描述

5.在兩個執行緒中使用類名先呼叫靜態加鎖方法再呼叫未加鎖靜態方法

public class Lab {
	public synchronized static void fun1()//靜態加鎖方法
	{
		System.out.println("呼叫加鎖方法");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("加鎖方法執行完畢");
	}
	public static void fun2()//將第二個方法也改成靜態的
	{
		System.out.println("呼叫未加鎖方法");
	}
}
public class Test {
	public static void main(String[] args) {
		new Thread(new Runnable() {
			public void run() {
				Lab.fun1();//呼叫加鎖方法
			}
		}).start();
		
		new Thread(new Runnable() {
			public void run() {
				Lab.fun2();//呼叫未加鎖方法
			}
		}).start();
	}
}

執行結果:
在這裡插入圖片描述
沒有鎖住

6.在兩個執行緒中使用類名先呼叫靜態加鎖方法再呼叫另一個靜態加鎖方法

public class Lab {
	public synchronized static void fun1()
	{
		System.out.println("呼叫加鎖方法");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("加鎖方法執行完畢");
	}
	public synchronized static void fun2()
	{
		System.out.println("呼叫未加鎖方法");
	}
}
public class Test {
	public static void main(String[] args) {
		new Thread(new Runnable() {
			public void run() {
				Lab.fun1();//呼叫加鎖方法
			}
		}).start();
		
		new Thread(new Runnable() {
			public void run() {
				Lab.fun2();//呼叫未加鎖方法
			}
		}).start();
	}
}

執行結果:
在這裡插入圖片描述
加鎖成功

7.在兩個執行緒中使用同一個類的一個物件呼叫加鎖靜態方法,另一個物件呼叫加鎖非靜態方法

public class Lab {
	public synchronized static void fun1()
	{
		System.out.println("呼叫加鎖方法");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("加鎖方法執行完畢");
	}
	public synchronized void fun2()
	{
		System.out.println("呼叫未加鎖方法");
	}
}

public class Test {
	public static void main(String[] args) {
		Lab lab1 = new Lab();
		Lab lab2 = new Lab();
		new Thread(new Runnable() {
			public void run() {
				lab1.fun1();//呼叫加鎖方法
			}
		}).start();
		
		new Thread(new Runnable() {
			public void run() {
				lab2.fun2();//呼叫未加鎖方法
			}
		}).start();
	}
}

執行結果:
在這裡插入圖片描述
加鎖失敗

8.在兩個執行緒中使用同一個類的兩個物件分別呼叫兩個 不同的加鎖靜態方法

public class Lab {
	public synchronized static void fun1()
	{
		System.out.println("呼叫加鎖方法");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("加鎖方法執行完畢");
	}
	public synchronized static void fun2()
	{
		System.out.println("呼叫未加鎖方法");
	}
}
public class Test {
	public static void main(String[] args) {
		Lab lab1 = new Lab();
		Lab lab2 = new Lab();
		new Thread(new Runnable() {
			public void run() {
				lab1.fun1();//呼叫加鎖方法
			}
		}).start();
		
		new Thread(new Runnable() {
			public void run() {
				lab2.fun2();//呼叫未加鎖方法
			}
		}).start();
	}
}

執行結果:
在這裡插入圖片描述
加鎖成功,證明了對static方法加鎖是對這個類的所有物件生效,鎖住的是整個類

9.在同一個物件兩個加鎖方法內分別呼叫同一個未加鎖非靜態方法

public class Lab {
	public int a = 0;
	public synchronized void fun1()
	{
		total();
	}
	public synchronized void fun2()
	{
		total();
	}
	public void total()
	{
		System.out.println("都呼叫的方法");
		for(int i=0;i<10000;i++)
		{
			a++;
		}
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("共同方法呼叫完畢");
	}
}
public class Test{
	public static void main(String[] args) {
		Lab lab = new lab();
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				lab.start();
			}
		}).start();
		
		new Thread(new Runnable() {
					
			@Override
			public void run() {
				lab.starta();
			}
		}).start();
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(lab.a);
	}
}

執行結果:
在這裡插入圖片描述
因為同步執行了兩遍total方法,所以a變數迴圈++了20000次
加鎖成功

10.在同一個物件兩個未加鎖方法內分別呼叫同一個加鎖非靜態方法

public class Lab {
	public int a = 0;
	public void fun1()
	{
		total();
	}
	public void fun2()
	{
		total();
	}
	public synchronized void total()
	{
		System.out.println("都呼叫的方法");
		for(int i=0;i<10000;i++)
		{
			a++;
		}
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("共同方法呼叫完畢");
	}
}
public class Test{
	public static void main(String
            
           

相關推薦

併發下不當,了!

> 本來是不打算寫這個文章但是在一個群裡面發現又有群友遇到和我一樣的問題不知道咋辦 ![](https://gitee.com/luoluo1995/image/raw/master/部落格圖片/20201126/20201126002.png) ## 知識點 1、併發(勉強) 2、mysql M

java使用synchronized區域實驗

我們都知道,java中可以使用synchronized對方法,或者變數加鎖,那麼,當我們使用synchronized對方法加鎖,對變數加鎖,shnchronized結合static一起使用,兩個普通方法同時呼叫一個使用synchronized方法等等情況下,會出現什麼樣的效果呢? 結論:

基於 Redis 的分散式實現及案例

關於分散式鎖的實現,目前常用的方案有以下三類:資料庫樂觀鎖;基於分散式快取實現的鎖服務,典型代表有 Redis 和基於 Redis 的 RedLock;基於分散式一致性演算法實現的鎖服務,典型代表有 ZooKeeper、Chubby 和 ETCD。本場 Chat 將介紹基於

SQL Server 實驗(SELECT探究)

style 一個 相關 select 當我 gin hold ria san 本例中使用begin tran和with (holdlock)提示來觀察SQL Server在select語句中的鎖。 開啟事務是為了保證時間極短的查詢也能觀察到鎖情況,因為holdlock會在事

Angular4.0之路:探索子路由和懶

ati clas per 而是 配置 trap child property one 參考文章: Angular4路由快速入門 http://www.jianshu.com/p/e72c79c6968e Angular2文檔學習的知識點摘要——Angular模塊(NgMo

Mongo 後臺索引

開始 但是 一分鐘 聯合 管理 阻塞 主從同步 鍵值 增長 背景,隨著mongo數據量變大,查詢效率變低,要對索引進行優化,所在公司對mongo依賴比較嚴重,而DBA並不對mongo的權限做控制,所以每個後端開發都有mongo的讀寫權限,通常每個人各自管理自己的模塊的數據。

重灌系統後,重新安裝ORACLE環境變數配置、客戶端PL/SQL的安裝過程,及注意事項(避免再次

(1)首先了解什麼是OERACLE及Oracle與PL/SQL是什麼關係: ORACLE是資料庫,有客戶端和伺服器; PLSQL Developer只是第三方工具,服務於ORACLE,類似的工具還有Toad,sqlplus,sql developer等等; 安裝PLSQL Developer

神舟+win10+ubuntu16.04+256GSSD+1THHD雙系統安裝openssl之旅

上海最近搞活動調休,要搞深度學習,win上還是不方便,準備弄個ubuntu。於是有以下回憶文字。 在機器上裝了個雙系統。花了兩天。再也不想玩了。 準備用ubuntu來做深度學習的。 本文寫於2019年11月4日。 機器是神舟Z7-KP7D2,i7-7700HQ+GTX1060(inter HD630)+256

程式設計師的經驗總結(四):死

死鎖也是程式設計師最常見的問題之一了,但是死鎖跟記憶體洩露不同,原理和原因都相對簡單,簡單說就是你等我,我也等你,就這麼耗著! 但死鎖的影響有時比記憶體洩露更嚴重。記憶體洩露主要是漸進式的,可能重啟一下就可以從頭開始了。而死鎖是重啟不了,這只是直接影響而已。死鎖一般會出現某個功能或者操作無反應,可能進一步沒有

sqlite ef6

div sqlite vid led sqlit 問題 clas tee ons 調試的時候配置寫如下,這樣寫是沒有問題的但是在實際環境中有問題,因為EF路徑找不到.會提示錯誤:The underlying provider failed on open <

】360安全瀏覽器“極速模式”和“兼容模式”,套路還是bug?

html 一個 另一個 地址 不生效 bug rom 論壇 val 分享踩坑點: 項目中需要兼容360安全瀏覽器,大家當然都希望用極速模式打開網站,但是發現總是被兼容模式打開 網址類似 aa.xx.dd.com 網上找了很多地方,有以下兩種方法 1.<m

】angularJS 1.X版本中 ng-bind 指令多空格展示

ext 數據庫查詢 sci 接收 可能 color 最終 數據 目的 做項目的時候遇到的問題 1、問題描述   用戶在表單某個值輸入多個空格,例如:A B,保存至服務器   在列表查詢頁面中使用bg-bind的指令單向綁定,結果展示位A B,連續的空格被替換

Uber使用Swift重寫APP的經歷及解決方案(轉載)

result 框架 退出 帶來 hole 懶漢 將在 例子 穩定 本文出自Uber移動架構和框架組負責人托馬斯·阿特曼於2016年在灣區Swift峰會上的演講,分享了使用Swfit重寫Uber的好與壞。以下為譯文: 我是托馬斯·阿特曼,目前是Uber移動架構和框架組負責人。

通過CAS避免

.com tom 變化 con cin blog 添加 讀取 ted package com.guo.day05; import java.util.concurrent.atomic.AtomicInteger; /** * Created by gu

Visual Studio For MacOS 記(二)

mirrors class app macosx andro mce 資料 library devel Visual Studio For MacOS安裝安卓SDK。 系統默認安裝了安卓6.0 API23的SDK。 但是我需要安卓7.0的,API24. 遂安裝。

caffe_ssd_

caff onf ini x86_64 share mailto rect x86 datum 一 http://blog.csdn.net/sinat_31802439/article/details/52958791 python.config no such file

java多線程讀一個變量需要嗎?

多線程 final關鍵字 一個 ati 關鍵字 java多線程 其他 同時 關聯 如果只是讀操作,沒有寫操作,則可以不用加鎖,此種情形下,建議變量加上final關鍵字; 如果有寫操作,但是變量的寫操作跟當前的值無關聯,且與其他的變量也無關聯,則可考慮變量加上volat

ReactNative系列--構建失敗

pos hone dia install works 沒有 iphone 註意 module 初始化項目後執行react-native run-ios,構建失敗: ** BUILD FAILED ** The following commands produced a

回顧vue開發spa(記錄)

url 如果 after 本質 {} spa 不能 cnblogs 所有     使用vueJS開發前端頁面差不多也有大半多年了。由於項目後臺管理頁面最早都是使用JQ進行開發的,剛開始使用vue的時候,只能是直接在頁面裏面引入vueJS框架進行開發,期間把項目後臺的編輯頁面

Laravel筆記——illuminate/html被拋棄

mina one lec define 文檔 onf acad lar require 起因 在使用如下代碼的時候發生報錯 {!! Form::open() !!}   錯誤信息 [Symfony\Component\Debug\Exception\