建議收藏 Java線程同步的四種方式詳解

?

建議收藏 Java線程同步的四種方式詳解

文章插圖
【建議收藏 Java線程同步的四種方式詳解】Java線程同步屬于Java多線程與并發編程的核心點,需要重點掌握,下面我就來詳解Java線程同步的4種主要的實現方式@mikechen
目錄
  • 什么是線程同步
  • 線程同步的幾種方式
    • 1、使用synchronized關鍵字
    • 2.使用ReentrantLock
    • 3.使用原子變量實現線程同步
    • 4.ThreadLocal實現線程同步
什么是線程同步當使用多個線程來訪問同一個數據時,將會導致數據不準確 , 相互之間產生沖突,非常容易出現線程安全問題,如下圖所示:
建議收藏 Java線程同步的四種方式詳解

文章插圖
比如多個線程都在操作同一數據,都打算修改商品庫存,這樣就會導致數據不一致的問題 。
線程同步的真實意思 , 其實是“排隊”:幾個線程之間要排隊 , 一個一個對共享資源進行操作,而不是同時進行操作 。
所以我們用同步機制來解決這些問題,加入同步鎖以避免在該線程沒有完成操作之前 , 被其他線程的調用,從而保證了該變量的唯一性和準確性 。
線程同步的幾種方式
建議收藏 Java線程同步的四種方式詳解

文章插圖
1、使用synchronized關鍵字這種方式比較靈活,修飾一個代碼塊,被修飾的代碼塊稱為同步語句塊 。
其作用的范圍是大括號{}括起來的代碼,作用的對象是調用這個代碼塊的對象,如下格式:
synchronized(對象) {//得到對象的鎖,才能操作同步代碼需要被同步代碼;}
建議收藏 Java線程同步的四種方式詳解

文章插圖
建議收藏 Java線程同步的四種方式詳解

文章插圖
通常沒有必要同步整個方法,使用synchronized代碼塊同步關鍵代碼即可 。
具體的示例如下:
public class SynchronizedThread {class Bank {private int account = 200;public int getAccount() {return account;}/*** 用同步方法實現** @param money*/public synchronized void save(int money) {account += money;}/*** 用同步代碼塊實現** @param money*/public void save1(int money) {synchronized (this) {account += money;}}}class NewThread implements Runnable {private Bank bank;public NewThread(Bank bank) {this.bank = bank;}@Overridepublic void run() {for (int i = 0; i < 10; i++) {// bank.save1(10);bank.save(10);System.out.println(i + "賬戶余額為:" + bank.getAccount());}}}/*** 建立線程 , 調用內部類*/public void useThread() {Bank bank = new Bank();NewThread new_thread = new NewThread(bank);System.out.println("線程1");Thread thread1 = new Thread(new_thread);thread1.start();System.out.println("線程2");Thread thread2 = new Thread(new_thread);thread2.start();}public static void main(String[] args) {SynchronizedThread st = new SynchronizedThread();st.useThread();}}
建議收藏 Java線程同步的四種方式詳解

文章插圖
2.使用ReentrantLockReentrantLock類是可重入、互斥、實現了Lock接口的鎖,它與使用synchronized方法具有相同的基本行為和語義,并且擴展了其能力 。
建議收藏 Java線程同步的四種方式詳解

文章插圖
private int account = 100;//需要聲明這個鎖private Lock lock = new ReentrantLock();public int getAccount() {return account;}//這里不再需要synchronizedpublic void save(int money) {lock.lock();try{account += money;}finally{lock.unlock();}}}synchronized 與 Lock 的對比
ReentrantLock是顯示鎖,手動開啟和關閉鎖 , 別忘記關閉鎖;
synchronized 是隱式鎖 , 出了作用域自動釋放;
ReentrantLock只有代碼塊鎖,synchronized 有代碼塊鎖和方法鎖;
使用 ReentrantLock鎖,JVM 將花費較少的時間來調度線程,線程更好,并且具有更好的擴展性(提供更多的子類);
優先使用順序:
ReentrantLock> synchronized 同步代碼塊> synchronized 同步方法
3.使用原子變量實現線程同步為了完成線程同步 , 我們將使用原子變量(Atomic***開頭的)來實現 。
比如典型代表:AtomicInteger類存在于java.util.concurrent.atomic中,該類表示支持原子操作的整數,采用getAndIncrement方法以原子方法將當前的值遞加 。
具體示例如下:
private AtomicInteger account = new AtomicInteger(100);public AtomicInteger getAccount() {return account;}public void save(int money) {account.addAndGet(money);}

推薦閱讀