本文實例講述了Java線程同步的用法。分享給大家供大家參考。具體分析如下:
多線程的使用為我們的程序提供了眾多的方便,同時它也給我們帶來了以往沒有考慮過的麻煩。當我們使用多線程處理共享資源時意外將會發生:比如我們一起外出就餐,每個人都是一個線程,餐桌上的食物則是共享資源,當我看到紅燒雞腿上桌後立即拿起筷子直奔目標,眼看著就得手的時候,突然~~~雞腿消失了,一個距離盤子更近的線程正在得意地啃著。
為了避免上述問題的發生,Java為我們提供了“synchronized(同步化)修飾符”來避免資源衝突,你可以將資源類中某個函數或變量聲明為synchronized(同步化),每個繼承自Object的類都含有一個機鎖(Lock),它是餘生俱來的,不需要編寫任何代碼來啟用它。當我們調用任何synchronized(同步化)函數時,該對象將被鎖定,對像中所有synchronized(同步化)函數便無法被調用,直到第一個函數執行完畢並解除機鎖。
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中進行線程同步的方法* 重點:synchronized修飾符*/public class TestMain5 extends JFrame { private MyAccounts myAccounts = null; // 我的帳號private JTextField text = null; // 銀行存款數額顯示private JTextArea textArea = null; // 交易過程顯示private JButton button = null; // 開始模擬交易的按鈕/** * 構造一個銀行存取款界面*/ 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個交易大廳,這些大廳可以同時處理多筆業務,這正好符合多線程的特點*/ class Bank extends Thread{ /** * 靜態字段:用於表示儲存*/ public static final int DEAL_SAVING = 0; /** * 靜態字段:用於表示提取*/ public static final int DEAL_FETCH = 1; private int buy = Bank.DEAL_FETCH; // 默認使取款private int count = 0; private MyAccounts myAccounts = null; // 我的帳號/** * 構造這個銀行交易大廳* @param name 這個交易大廳的名稱* @ param myAccounts 我的銀行帳號* @param buy 行為,參考字段:DEAL_SAVING或DEAL_FETCH * @param count 錢的數量*/ 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){ // 如果是存款業務$count = myAccounts.saving(count); }else if(buy == Bank.DEAL_FETCH){ // 如果是取款業務$count = myAccounts.fetch(count); } text.setText(Integer.toString($count )); textArea.append("/n" + this.getName() + " " + (buy == Bank.DEAL_SAVING ? "存款": "取款") + " 金額:" + count + " 結餘:" + $count); } } /** * 我的帳號* 進行同步測試*/ class MyAccounts{ private Integer count = 1100; public MyAccounts(){ } /** * 查詢我的帳號*/ public int inquire(){ synchronized (count){ return count; } } /** * 存款業務* @param c 存款的數量* @return 業務辦理完成後的數量*/ public int saving(int c){ synchronized (count){ //return count += c; // 為了能更好的觀察,我們將這個簡潔的語句註釋掉int $count = inquire(); // 先查詢帳戶中的存款$count += c; try { Thread.sleep( 1000); // 為了更好的觀察,使業務在此停頓1秒鐘} catch (InterruptedException ex) { ex.printStackTrace(); } count = $count; // 最後將總數儲存起來return inquire(); // 返回最新的存款數} } /** * 取款業務* @param c 取款的數量* @return 業務辦理完成後的數量*/ public int fetch(int c){ synchronized (count){ //return count -= c; // 為了能更好的觀察,我們將這個簡潔的語句註釋掉int $count = inquire(); // 先查詢帳戶中的存款$count -= c; try { Thread.sleep(1000 ); // 為了更好的觀察,使業務在此停頓1秒鐘} catch (InterruptedException ex) { ex.printStackTrace(); } count = $count; // 最後將總數儲存起來return inquire(); / / 返回最新的存款數} } } public static void main(String [] args){ new TestMain5(); }}希望本文所述對大家的java程序設計有所幫助。