由于同一行程的多個執行緒共享一塊存盤空間,在帶來方便的同時,也帶來了訪問沖突問題,為了保證資料在方法中被訪問是的正確性,在訪問時加入鎖機制synchronized,當一個執行緒獲得物件的排它鎖,獨占資源,其他執行緒必須等待,使用后釋放鎖即可,存在以下問題:
- 一個執行緒持有鎖會導致其他所有需要此鎖掛起;
- 在多執行緒競爭下,加鎖,釋放鎖會導致比較多的背景關系切換 和 調度延時,引起性能問題;
- 如果一個優先級高的執行緒等待一個優先級低的執行緒釋放鎖 會導致優先級倒置,引起性能問題,
同步方法
-
由于我們可以通過private關鍵字來保證資料物件只能被方法訪問,所以我們只需要針對方法提出一套機制,這套機制就是synchronized關鍵字,它包括兩種用法:synchronized方法 和 synchronized塊,
同步方法:public synchronized void method(int args){}
塊:synchronized(this){}
-
synchronized方法控制對”物件“的訪問,每個物件對應一把鎖,每個synchronized方法都必須獲得調該方法的物件的鎖才能執行,否則執行緒會阻塞,方法一旦執行,就獨占該鎖,直到該方法回傳才釋放鎖,后面被阻塞的執行緒才能獲取這個鎖,繼續執行,
缺陷:若將一個大的方法申明為synchronized將會影響效率
同步方法弊端
- 方法里面需要修改的內容才需要鎖,鎖定太多,浪費資源
同步塊
- 同步塊:synchronized(Obj){}
- Obj 稱之為 同步監視器
- Obj 可以是任何物件,但是推薦使用共享資源作為同步監視器
- 同步方法中無需指定同步監視器,因為同步方法的同步監視器就是this,就是這個物件本身,或者是class【反射中講解】
- 同步監視器的執行程序
- 第一個執行緒訪問,鎖定同步監視器,執行其中代碼,
- 第二個執行緒訪問,發現同步監視器被鎖定,無法訪問,
- 第一個執行緒訪問完畢,解鎖同步監視器,
- 第二個執行緒訪問,發現同步監視器沒有鎖,然后鎖定并訪問
不安全案例修改為安全案例
案例一:
public class UnsafeBuyTicket {
public static void main(String[] args) {
BuyTicket b = new BuyTicket();
new Thread(b,"老黃牛").start();
new Thread(b,"網友").start();
new Thread(b,"自己").start();
}
}
class BuyTicket implements Runnable{
// 票
private int ticetNum = 10;
// 外部停止方式
boolean flag = true;
@Override
public void run() {
// 買票
while (flag){
buy();
}
}
// synchronized 同步方法,鎖的是this
private synchronized void buy(){
// 判斷是否有票
if(ticetNum<=0){
flag = false;
return;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 買票
System.out.println(Thread.currentThread().getName()+"拿到"+ticetNum--);
}
}
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-mPvMWuv9-1617869030711)(D:\學習\tupian\多執行緒\執行緒同步\dui1.png)]](https://img.uj5u.com/2021/04/09/234786091144301.png)
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-QkTkaj9U-1617869030715)(D:\學習\tupian\多執行緒\執行緒同步\dui1_s.png)]](https://img.uj5u.com/2021/04/09/234786091144302.png)
就這么簡單
案例二:
// 兩個人去銀行賬戶,取錢
public class UnsafeBank {
public static void main(String[] args) {
// 賬戶
Account account = new Account("專案基金",1001);
Drawing you = new Drawing(account,50,"組長");
Drawing my = new Drawing(account,80,"組員");
you.start();
my.start();
}
}
class Account{
String name;
int money;
public Account(String name, int yue) {
this.name = name;
this.money = yue;
}
}
// 銀行:模擬取錢
class Drawing extends Thread{
Account account;// 賬戶
// 取了多少錢
int drawingMoney;
// 現在手里有多少錢
int nowMoney;
public Drawing(Account account,int drawingMoney,String name){
super(name);
this.account = account;
this.drawingMoney = drawingMoney;
}
// 取錢
@Override
public void run() {
// synchronized默認鎖的是this 就是它本身
// synchronized塊可以鎖任何物件
// 鎖的物件就是變化的量,需要增刪改的物件
synchronized (account){
// 判斷有沒有錢
if (account.money-drawingMoney<0){
System.out.println(this.getName()+"沒錢了,取不了");
return;
}
// sleep可以放大問題的發生性
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 卡內余額 = 余額 - 你取的錢
account.money -= drawingMoney;
// 你手里的錢
nowMoney += drawingMoney;
System.out.println(account.name+"余額為:"+account.money);
System.out.println(this.getName()+"手里的錢"+nowMoney);
}
}
}

![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-4P8teuwq-1617869030721)(D:\學習\tupian\多執行緒\執行緒同步\dui2_s.png)]](https://img.uj5u.com/2021/04/09/234786091144304.png)
為什么不把run方法鎖了呢?那是因為synchronized默認鎖的是this 就是本身,synchronized方法不能改變鎖住的是誰,只能鎖this,所以如果把run變成同步鎖,就相當于把銀行類鎖了,你說人取錢你把銀行鎖了,那不白鎖嗎
案例三:
public class UnsafeList {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
for(int i = 0;i<10000;i++){
new Thread(()->{
synchronized (list){
list.add(Thread.currentThread().getName());
}
}).start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-VgfEwzMQ-1617869030726)(D:\學習\tupian\多執行緒\執行緒同步\dui3.png)]](https://img.uj5u.com/2021/04/09/234786091144305.png)
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-FnMn2ftY-1617869030729)(D:\學習\tupian\多執行緒\執行緒同步\dui3_s.png)]](https://img.uj5u.com/2021/04/09/234786091144306.png)
總結:
很簡單,實際上就是把方法變成了同步方法或用同步塊套住你變化的量,雖然解決了問題,但是如果是一個很大的方法變成了同步方法會降低效率,但變得安全了,畢竟魚和熊掌不能兼得,
- 下面是《不安全案例》鏈接,看一看會對同步理解的更快
Java-----多執行緒【并發與三大不安全案例】
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/274161.html
標籤:其他
下一篇:網路安全基礎——HLCA綜合實驗
