|NO.Z.00102|——————————|BigDataEnd|——|Java&多執行緒.V14|------------------------------------------------|Java.v14|執行緒同步機制|概念由來|同步程式碼塊實現執行緒同步方式|
阿新 • • 發佈:2022-04-04
[BigDataJava:Java&多執行緒.V14] [BigDataJava.核心類庫] [|執行緒同步機制的概念和由來|同步程式碼塊實現執行緒同步的方式一|同步方法實現執行緒同步的方式二|]
一、執行緒同步機制的概念和由來
### --- 執行緒同步機制的概念和由來 ——> [執行緒同步機制的概念和由來] ——> [同步程式碼塊實現執行緒同步的方式一] ——> [同步方法實現執行緒同步的方式二]
### --- 執行緒同步機制(重點)
### --- 基本概念
——> 當多個執行緒同時訪問同一種共享資源時,可能會造成資料的覆蓋等不一致性問題,此時就需要對執行緒之間進行通訊和協調,該機制就叫做執行緒的同步機制。
——> 多個執行緒併發讀寫同一個臨界資源時會發生執行緒併發安全問題。
——> 非同步操作:多執行緒併發的操作,各自獨立執行。
——> 同步操作:多執行緒序列的操作,先後執行的順序。
### --- 解決方案 ——> 由程式結果可知:當兩個執行緒同時對同一個賬戶進行取款時,導致最終的賬戶餘額不合理。 ——> 引發原因:執行緒一執行取款時還沒來得及將取款後的餘額寫入後臺,執行緒二就已經開始取款。 ——> 解決方案:讓執行緒一執行完畢取款操作後,再讓執行緒二執行即可,將執行緒的併發操作改為序列操作。 ——> 經驗分享:在以後的開發儘量減少序列操作的範圍,從而提高效率。
二、程式設計程式碼### --- 實現方式 ——> 在Java語言中使用synchronized關鍵字來實現同步/物件鎖機制從而保證執行緒執行的原子性,具體方式如下: ——> 使用同步程式碼塊的方式實現部分程式碼的鎖定,格式如下: ——> synchronized(類型別的引用) { ——> 編寫所有需要鎖定的程式碼; ——> } ——> 使用同步方法的方式實現所有程式碼的鎖定。 ——> 直接使用synchronized關鍵字來修飾整個方法即可 ——> 該方式等價於: ——> synchronized(this) { 整個方法體的程式碼 }
package com.yanqi.task18;
import java.util.concurrent.locks.ReentrantLock;
public class AccountRunnableTest implements Runnable {
private int balance; // 用於描述賬戶的餘額
private Demo dm = new Demo();
private ReentrantLock lock = new ReentrantLock(); // 準備了一把鎖
public AccountRunnableTest() {
}
public AccountRunnableTest(int balance) {
this.balance = balance;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
@Override
public /*synchronized*/ void run() {
// 開始加鎖
lock.lock();
// 由原始碼可知:最終是account物件來呼叫run方法,因此當前正在呼叫的物件就是account,也就是說this就是account
//synchronized (this) { // ok
System.out.println("執行緒" + Thread.currentThread().getName() + "已啟動...");
//synchronized (dm) { // ok
//synchronized (new Demo()) { // 鎖不住 要求必須是同一個物件
// 1.模擬從後臺查詢賬戶餘額的過程
int temp = getBalance(); // temp = 1000 temp = 1000
// 2.模擬取款200元的過程
if (temp >= 200) {
System.out.println("正在出鈔,請稍後...");
temp -= 200; // temp = 800 temp = 800
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("請取走您的鈔票!");
} else {
System.out.println("餘額不足,請核對您的賬戶餘額!");
}
// 3.模擬將最新的賬戶餘額寫入到後臺
setBalance(temp); // balance = 800 balance = 800
//}
lock.unlock(); // 實現解鎖
}
public static void main(String[] args) {
AccountRunnableTest account = new AccountRunnableTest(1000);
//AccountRunnableTest account2 = new AccountRunnableTest(1000);
Thread t1 = new Thread(account);
Thread t2 = new Thread(account);
//Thread t2 = new Thread(account2);
t1.start();
t2.start();
System.out.println("主執行緒開始等待...");
try {
t1.join();
//t2.start(); // 也就是等待執行緒一取款操作結束後再啟動執行緒二
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("最終的賬戶餘額為:" + account.getBalance()); // 600 800
}
}
class Demo{}
三、編譯列印
D:\JAVA\jdk-11.0.2\bin\java.exe "-javaagent:D:\IntelliJIDEA\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=51045:D:\IntelliJIDEA\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath E:\NO.Z.10000——javaproject\NO.H.00001.javase\javase\out\production\javase com.yanqi.task18.AccountRunnableTest
主執行緒開始等待...
執行緒Thread-0已啟動...
正在出鈔,請稍後...
請取走您的鈔票!
執行緒Thread-1已啟動...
正在出鈔,請稍後...
請取走您的鈔票!
最終的賬戶餘額為:600
Process finished with exit code 0
===============================END===============================
Walter Savage Landor:strove with none,for none was worth my strife.Nature I loved and, next to Nature, Art:I warm'd both hands before the fire of life.It sinks, and I am ready to depart ——W.S.Landor
來自為知筆記(Wiz)