Java線程同步實例分析
本文實例講述了Java線程同步的用法。分享給大家供大家參考。具體分析如下:
多線程的使用為我們的程序提供了眾多的方便,同時它也給我們帶來了以往沒有考慮過的麻煩。當(dāng)我們使用多線程處理共享資源時意外將會發(fā)生:比如我們一起外出就餐,每個人都是一個線程,餐桌上的食物則是共享資源,當(dāng)我看到紅燒雞腿上桌后立即拿起筷子直奔目標(biāo),眼看著就得手的時候,突然~~~雞腿消失了,一個距離盤子更近的線程正在得意地啃著。
為了避免上述問題的發(fā)生,Java為我們提供了“synchronized(同步化)修飾符”來避免資源沖突,你可以將資源類中某個函數(shù)或變量聲明為synchronized(同步化),每個繼承自O(shè)bject的類都含有一個機鎖(Lock),它是余生俱來的,不需要編寫任何代碼來啟用它。當(dāng)我們調(diào)用任何synchronized(同步化)函數(shù)時,該對象將被鎖定,對象中所有 synchronized(同步化)函數(shù)便無法被調(diào)用,直到第一個函數(shù)執(zhí)行完畢并解除機鎖。
import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; /** * 線程同步 * 我們模擬一個銀行存儲過程來證明線程同步的必要性以及在Java中進(jìn)行線程同步的方法 * 重點:synchronized 修飾符 */ public class TestMain5 extends JFrame { private MyAccounts myAccounts = null; // 我的帳號 private JTextField text = null; // 銀行存款數(shù)額顯示 private JTextArea textArea = null; // 交易過程顯示 private JButton button = null; // 開始模擬交易的按鈕 /** * 構(gòu)造一個銀行存取款界面 */ public TestMain5(){ super("線程同步測試"); myAccounts = new MyAccounts(); text = new JTextField(Integer.toString(myAccounts.inquire()), 10); // 我們在銀行中的初始存款為100 textArea = new JTextArea(); textArea.setText("交易日志:"); JScrollPane sp = new JScrollPane(textArea); button = new JButton("開始交易"); button.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { new Bank("鐘樓支行", myAccounts, Bank.DEAL_SAVING, 800); new Bank("高新支行", myAccounts, Bank.DEAL_SAVING, 1300); new Bank("小寨支行", myAccounts, Bank.DEAL_FETCH, 200); new Bank("雁塔支行", myAccounts, Bank.DEAL_FETCH, 400); new Bank("興慶支行", myAccounts, Bank.DEAL_SAVING, 100); new Bank("土門支行", myAccounts, Bank.DEAL_FETCH, 700); } }); JPanel pane = new JPanel(); pane.add(text); pane.add(button); this.getContentPane().add(pane, BorderLayout.NORTH); this.getContentPane().add(sp); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(300, 200); this.setLocationRelativeTo(null); this.setVisible(true); } /** * 銀行交易大廳類 * 一般銀行都會有N個交易大廳,這些大廳可以同時處理多筆業(yè)務(wù),這正好符合多線程的特點 */ class Bank extends Thread{ /** * 靜態(tài)字段:用于表示儲存 */ public static final int DEAL_SAVING = 0; /** * 靜態(tài)字段:用于表示提取 */ public static final int DEAL_FETCH = 1; private int buy = Bank.DEAL_FETCH; // 默認(rèn)使取款 private int count = 0; private MyAccounts myAccounts = null; // 我的帳號 /** * 構(gòu)造這個銀行交易大廳 * @param name 這個交易大廳的名稱 * @param myAccounts 我的銀行帳號 * @param buy 行為,參考字段:DEAL_SAVING或DEAL_FETCH * @param count 錢的數(shù)量 */ public Bank(String name, MyAccounts myAccounts, int buy, int count){ super(name); this.myAccounts = myAccounts; this.buy = buy; this.count = count; this.start(); } public void run(){ int $count = 0; if(buy == Bank.DEAL_SAVING){ // 如果是存款業(yè)務(wù) $count = myAccounts.saving(count); }else if(buy == Bank.DEAL_FETCH){ // 如果是取款業(yè)務(wù) $count = myAccounts.fetch(count); } text.setText(Integer.toString($count)); textArea.append("\n" + this.getName() + " " + (buy == Bank.DEAL_SAVING ? "存款": "取款") + " 金額:" + count + " 結(jié)余:" + $count); } } /** * 我的帳號 * 進(jìn)行同步測試 */ class MyAccounts{ private Integer count = 1100; public MyAccounts(){ } /** * 查詢我的帳號 */ public int inquire(){ synchronized (count){ return count; } } /** * 存款業(yè)務(wù) * @param c 存款的數(shù)量 * @return 業(yè)務(wù)辦理完成后的數(shù)量 */ public int saving(int c){ synchronized (count){ //return count += c; // 為了能更好的觀察,我們將這個簡潔的語句注釋掉 int $count = inquire(); // 先查詢帳戶中的存款 $count += c; try { Thread.sleep(1000); // 為了更好的觀察,使業(yè)務(wù)在此停頓1秒鐘 } catch (InterruptedException ex) { ex.printStackTrace(); } count = $count; // 最后將總數(shù)儲存起來 return inquire(); // 返回最新的存款數(shù) } } /** * 取款業(yè)務(wù) * @param c 取款的數(shù)量 * @return 業(yè)務(wù)辦理完成后的數(shù)量 */ public int fetch(int c){ synchronized (count){ //return count -= c; // 為了能更好的觀察,我們將這個簡潔的語句注釋掉 int $count = inquire(); // 先查詢帳戶中的存款 $count -= c; try { Thread.sleep(1000); // 為了更好的觀察,使業(yè)務(wù)在此停頓1秒鐘 } catch (InterruptedException ex) { ex.printStackTrace(); } count = $count; // 最后將總數(shù)儲存起來 return inquire(); // 返回最新的存款數(shù) } } } public static void main(String [] args){ new TestMain5(); } }
希望本文所述對大家的java程序設(shè)計有所幫助。
相關(guān)文章
Springboot中com.mysql.cj.jdbc.Driver在yml文件中爆紅的原因解讀
這篇文章主要介紹了Springboot中com.mysql.cj.jdbc.Driver在yml文件中爆紅的原因解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-05-05解決mybatis三表連接查詢數(shù)據(jù)重復(fù)的問題
這篇文章主要介紹了解決mybatis三表連接查詢數(shù)據(jù)重復(fù)的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-01-01詳解Spring 參數(shù)驗證@Validated和@Valid的區(qū)別
這篇文章主要介紹了詳解參數(shù)驗證 @Validated 和 @Valid 的區(qū)別,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01使用springboot單元測試對weblistener的加載測試
這篇文章主要介紹了使用springboot單元測試對weblistener的加載測試,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10五分鐘教你手寫 SpringBoot 本地事務(wù)管理實現(xiàn)
這篇文章主要介紹了五分鐘教你手寫 SpringBoot 本地事務(wù)管理實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02淺談Redis在微服務(wù)架構(gòu)中的幾種應(yīng)用場景
本文介紹在SpringCloud中使用Redis作為Pub/Sub異步通信、緩存或主數(shù)據(jù)庫和配置服務(wù)器的三種場景應(yīng)用。小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-05-05