Java執行緒同步詳解
阿新 • • 發佈:2021-08-08
一、多執行緒執行問題
1、各個執行緒是通過競爭CPU時間而獲得執行機會的
2、各執行緒什麼時候得到CPU時間,佔用多久,是不可預測的
3、一個正在執行著的執行緒在什麼地方被暫停是不確定的
二、執行緒同步
為了解決上述問題,確保共享物件在同一時間只允許被一個執行緒訪問,即執行緒同步,可以使用synchronized和lock來實現。
三、synchronized的使用方式
1、修飾一個程式碼塊,被修飾的程式碼塊稱為同步程式碼塊,作用範圍是大括號{}括起來的程式碼;
2、修飾一個方法,被修飾的方法稱為同步方法,其作用範圍是整個方法;
3、修飾一個靜態方法,作用範圍是整個靜態方法;
例程(銀行存取款)
Class Bank
package com.imooc.bank; public class Bank { private String account;//賬號 private int balance;//賬戶餘額 public Bank(String account,int balane){ this.account=account; this.balance=balane; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public int getBalance() { return balance; } public void setBalance(int balance) { this.balance = balance; } @Override public String toString() { return "Bank[賬號:"+account+",餘額:"+balance+"]"; } //存款 public synchronized void saveAccount(){ //獲取當前的賬戶餘額 int balance=getBalance(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //修改金額,存100元 balance+=100; //修改賬餘額 setBalance(balance); //輸出存款後的賬戶餘額 System.out.println("存款後的賬戶餘額為:"+balance); } public void drawAccount(){ synchronized (this){ //獲得當前賬戶餘額 int balance=getBalance(); balance=balance-200; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } setBalance(balance); System.out.println("取款後的賬戶餘額:"+balance); } } }
Class DrawAccount 取款
package com.imooc.bank;
public class DrawAccount implements Runnable{
Bank bank;
public DrawAccount(Bank bank){
this.bank=bank;
}
@Override
public void run() {
bank.drawAccount();
}
}
Class SaveAccount 存款
package com.imooc.bank; public class SaveAccount implements Runnable{ Bank bank; public SaveAccount(Bank bank){ this.bank=bank; } @Override public void run() { bank.saveAccount(); } }
Class Test 測試類
package com.imooc.bank;
public class Test {
public static void main(String[] args) {
//建立賬戶,給定餘額為10000
Bank bank=new Bank("1001",1000);
//建立執行緒物件
SaveAccount sa=new SaveAccount(bank);
DrawAccount da=new DrawAccount(bank);
Thread save=new Thread(sa);
Thread draw=new Thread(da);
save.start();
draw.start();
try {
draw.join();
save.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(bank);
}
}
經過測試,當不加入synchronized實現執行緒同步時,存款取款的賬戶餘額會發生錯誤,
這裡使用執行緒延時模擬了執行緒被打斷的情況,當存款沒完全進行完時打斷了此執行緒進行取款
此時取款後的餘額不正確。
當加入了執行緒同步後,此問題得到了解決。
lock的使用方式
1、synchroized同步的時候,其中一條執行緒用完會自動釋放鎖,而Lock需要手動釋放,如果不手動釋放,可能造成死鎖
2、使用synchronized如果其中一個執行緒不釋放鎖,那麼其他需要獲取鎖的執行緒會一直等待下取,直到使用完釋放或者出現異常,
而Lock可以使用響應中斷或者使用規定等待時間的鎖
3、synchronized無法得知是否獲取到鎖,而Lock可以做到
4、用ReadWriteLock可以提高多個執行緒進行讀操作的笑了
lock簡單的使用方法
//建立lock物件
Lock lock=new ReentrantLock();
//手動加鎖
lock.lock();
try{
// 處理
}catch(Exception ex){
// 捕獲異常
}finally{
// 釋放鎖
lock.unlock();
}
你以為的極限,也許只是別人的起點