執行緒的同步是Java多執行緒程式設計的難點,往往開發者搞不清楚什麼是競爭資源、什麼時候需要考慮同步,怎麼同步等等問題,當然,這些問題沒有很明確的答案,但有些原則問題需要考慮,是否有競爭資源被同時改動的問題?以下僅供參考!
對於同步,在具體的Java程式碼中需要完成一下兩個操作:把競爭訪問的資源標識為private;同步哪些修改變數的程式碼,使用synchronized關鍵字同步方法或程式碼。當然這不是唯一控制併發安全的途徑。synchronized關鍵字使用說明synchronized只能標記非抽象的方法,不能標識成員變數。為了演示同步方法的使用,構建了一個信用卡賬戶,起初信用額為100w,然後模擬透支、存款等多個操作。顯然銀行賬戶User物件是個競爭資源,而多個併發操作的是賬戶方法oper(int x),當然應該在此方法上加上同步,並將賬戶的餘額設為私有變數,禁止直接訪問。
/**
* Java執行緒:執行緒的同步
*
* @author leizhimin 2009-11-4 11:23:32
*/
public class Test {
public static void main(String[] args) {
User u = new User(“張三”, 100);
MyThread t1 = new MyThread(“執行緒A”, u, 20);
MyThread t2 = new MyThread(“執行緒B”, u, -60);
MyThread t3 = new MyThread(“執行緒C”, u, -80);
MyThread t4 = new MyThread(“執行緒D”, u, -30);
MyThread t5 = new MyThread(“執行緒E”, u, 32);
MyThread t6 = new MyThread(“執行緒F”, u, 21);
t();
t();
t();
t();
t();
t();
}
}
class MyThread extends Thread {
private User u;
private int y = 0;
MyThread(String name, User u, int y) {
super(name);
this.u = u;
this.y = y;
}
public void run() {
(y);
}
}
class User {
private String code;
private int cash;
User(String code, int cash) {
= code;
= cash;
}
public String getCode() {
return code;
}
public void setCode(String code) {
= code;
}
/**
* 業務方法
* @param x 新增x萬元
*/
public synchronized void oper(int x) {
try {
p(10L);
+= x;
tln(entThread()。getName() + “執行結束,增加” + x + “”,“當前使用者賬戶餘額為:” + cash);
p(10L);
} catch (InterruptedException e) {
tStackTrace();
}
}
@Override
public String toString() {
return “User{” + “code=‘” + code + ’‘’ + “, cash=” + cash +‘}’;
}
}
輸出結果:執行緒A執行結束,增加“20”,當前使用者賬戶餘額為:120.
執行緒F執行結束,增加“21”,當前使用者賬戶餘額為:141.
執行緒E執行結束,增加“32”,當前使用者賬戶餘額為:173.
執行緒C執行結束,增加“-80”,當前使用者賬戶餘額為:93.
執行緒B執行結束,增加“-60”,當前使用者賬戶餘額為:33.
執行緒D執行結束,增加“-30”,當前使用者賬戶餘額為:3.
Process finished with exit code 0反面教材,不同步的情況,也就是去掉oper(int x)方法的synchronized修飾符,然後執行程式,結果如下:執行緒A執行結束,增加“20”,當前使用者賬戶餘額為:61.
執行緒D執行結束,增加“-30”,當前使用者賬戶餘額為:63.
執行緒B執行結束,增加“-60”,當前使用者賬戶餘額為:3.
執行緒F執行結束,增加“21”,當前使用者賬戶餘額為:61.
執行緒E執行結束,增加“32”,當前使用者賬戶餘額為:93.
執行緒C執行結束,增加“-80”,當前使用者賬戶餘額為:61.
Process finished with exit code 0很顯然,上面的結果是錯誤的,導致錯誤的原因是多個執行緒併發訪問了競爭資源u,並對u的屬性做了改動。可見同步的重要性。注意:通過前文可知,執行緒退出同步方法時將釋放掉方法所屬物件的鎖,但還應該注意的是,同步方法中還可以使用特定的方法對執行緒進行排程。這些方法來自於ct類,void notify()。
喚醒在此物件監視器上等待的`單個執行緒。
void notifyAll()
喚醒在此物件監視器上等待的所有執行緒。
void wait()
導致當前的執行緒等待,直到其他執行緒呼叫此物件的 notify() 方法或 notifyAll() 方法。
void wait(long timeout)
導致當前的執行緒等待,直到其他執行緒呼叫此物件的 notify() 方法或 notifyAll() 方法,或者超過指定的時間量。
void wait(long timeout, int nanos)
導致當前的執行緒等待,直到其他執行緒呼叫此物件的 notify() 方法或 notifyAll() 方法,或者其他某個執行緒中斷當前執行緒,或者已超過某個實際時間量。