本文實例講述了Java線程同步的用法。分享給大家供大家參考。具體分析如下:
多線程的使用為我們的程序提供了眾多的方便,同時它也給我們帶來了以往沒有考慮過的麻煩。當我們使用多線程處理共享資源時意外將會發生:比如我們一起外出就餐,每個人都是一個線程,餐桌上的食物則是共享資源,當我看到紅燒雞腿上桌后立即拿起筷子直奔目標,眼看著就得手的時候,突然~~~雞腿消失了,一個距離盤子更近的線程正在得意地啃著。
為了避免上述問題的發生,Java為我們提供了“synchronized(同步化)修飾符”來避免資源沖突,你可以將資源類中某個函數或變量聲明為synchronized(同步化),每個繼承自Object的類都含有一個機鎖(Lock),它是余生俱來的,不需要編寫任何代碼來啟用它。當我們調用任何synchronized(同步化)函數時,該對象將被鎖定,對象中所有 synchronized(同步化)函數便無法被調用,直到第一個函數執行完畢并解除機鎖。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
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程序設計有所幫助。