- 相關(guān)推薦
Java線(xiàn)程同步的方法
線(xiàn)程的同步是Java多線(xiàn)程編程的難點(diǎn),往往開(kāi)發(fā)者搞不清楚什么是競(jìng)爭(zhēng)資源、什么時(shí)候需要考慮同步,怎么同步等等問(wèn)題,當(dāng)然,這些問(wèn)題沒(méi)有很明確的答案,但有些原則問(wèn)題需要考慮,是否有競(jìng)爭(zhēng)資源被同時(shí)改動(dòng)的問(wèn)題?
對(duì)于同步,在具體的Java代碼中需要完成一下兩個(gè)操作:把競(jìng)爭(zhēng)訪(fǎng)問(wèn)的資源標(biāo)識(shí)為private;同步哪些修改變量的代碼,使用synchronized關(guān)鍵字同步方法或代碼。當(dāng)然這不是唯一控制并發(fā)安全的途徑。synchronized關(guān)鍵字使用說(shuō)明synchronized只能標(biāo)記非抽象的方法,不能標(biāo)識(shí)成員變量。為了演示同步方法的使用,構(gòu)建了一個(gè)信用卡賬戶(hù),起初信用額為100w,然后模擬透支、存款等多個(gè)操作。顯然銀行賬戶(hù)User對(duì)象是個(gè)競(jìng)爭(zhēng)資源,而多個(gè)并發(fā)操作的是賬戶(hù)方法oper(int x),當(dāng)然應(yīng)該在此方法上加上同步,并將賬戶(hù)的余額設(shè)為私有變量,禁止直接訪(fǎng)問(wèn)。
/**
* Java線(xiàn)程:線(xiàn)程的同步
*
* @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(“線(xiàn)程A”, u, 20);
MyThread t2 = new MyThread(“線(xiàn)程B”, u, -60);
MyThread t3 = new MyThread(“線(xiàn)程C”, u, -80);
MyThread t4 = new MyThread(“線(xiàn)程D”, u, -30);
MyThread t5 = new MyThread(“線(xiàn)程E”, u, 32);
MyThread t6 = new MyThread(“線(xiàn)程F”, u, 21);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}
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() {
u.oper(y);
}
}
class User {
private String code;
private int cash;
User(String code, int cash) {
this.code = code;
this.cash = cash;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
/**
* 業(yè)務(wù)方法
* @param x 添加x萬(wàn)元
*/
public synchronized void oper(int x) {
try {
Thread.sleep(10L);
this.cash += x;
System.out.println(Thread.currentThread()。getName() + “運(yùn)行結(jié)束,增加” + x + “”,“當(dāng)前用戶(hù)賬戶(hù)余額為:” + cash);
Thread.sleep(10L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return “User{” + “code=‘” + code + ’\‘’ + “, cash=” + cash +‘}’;
}
}
輸出結(jié)果:線(xiàn)程A運(yùn)行結(jié)束,增加“20”,當(dāng)前用戶(hù)賬戶(hù)余額為:120.
線(xiàn)程F運(yùn)行結(jié)束,增加“21”,當(dāng)前用戶(hù)賬戶(hù)余額為:141.
線(xiàn)程E運(yùn)行結(jié)束,增加“32”,當(dāng)前用戶(hù)賬戶(hù)余額為:173.
線(xiàn)程C運(yùn)行結(jié)束,增加“-80”,當(dāng)前用戶(hù)賬戶(hù)余額為:93.
線(xiàn)程B運(yùn)行結(jié)束,增加“-60”,當(dāng)前用戶(hù)賬戶(hù)余額為:33.
線(xiàn)程D運(yùn)行結(jié)束,增加“-30”,當(dāng)前用戶(hù)賬戶(hù)余額為:3.
Process finished with exit code 0反面教材,不同步的情況,也就是去掉oper(int x)方法的synchronized修飾符,然后運(yùn)行程序,結(jié)果如下:線(xiàn)程A運(yùn)行結(jié)束,增加“20”,當(dāng)前用戶(hù)賬戶(hù)余額為:61.
線(xiàn)程D運(yùn)行結(jié)束,增加“-30”,當(dāng)前用戶(hù)賬戶(hù)余額為:63.
線(xiàn)程B運(yùn)行結(jié)束,增加“-60”,當(dāng)前用戶(hù)賬戶(hù)余額為:3.
線(xiàn)程F運(yùn)行結(jié)束,增加“21”,當(dāng)前用戶(hù)賬戶(hù)余額為:61.
線(xiàn)程E運(yùn)行結(jié)束,增加“32”,當(dāng)前用戶(hù)賬戶(hù)余額為:93.
線(xiàn)程C運(yùn)行結(jié)束,增加“-80”,當(dāng)前用戶(hù)賬戶(hù)余額為:61.
Process finished with exit code 0很顯然,上面的結(jié)果是錯(cuò)誤的,導(dǎo)致錯(cuò)誤的原因是多個(gè)線(xiàn)程并發(fā)訪(fǎng)問(wèn)了競(jìng)爭(zhēng)資源u,并對(duì)u的屬性做了改動(dòng)?梢(jiàn)同步的重要性。注意:通過(guò)前文可知,線(xiàn)程退出同步方法時(shí)將釋放掉方法所屬對(duì)象的鎖,但還應(yīng)該注意的是,同步方法中還可以使用特定的方法對(duì)線(xiàn)程進(jìn)行調(diào)度。這些方法來(lái)自于java.lang.Object類(lèi),void notify()。
喚醒在此對(duì)象監(jiān)視器上等待的單個(gè)線(xiàn)程。
void notifyAll()
喚醒在此對(duì)象監(jiān)視器上等待的所有線(xiàn)程。
void wait()
導(dǎo)致當(dāng)前的線(xiàn)程等待,直到其他線(xiàn)程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 方法。
void wait(long timeout)
導(dǎo)致當(dāng)前的線(xiàn)程等待,直到其他線(xiàn)程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 方法,或者超過(guò)指定的時(shí)間量。
void wait(long timeout, int nanos)
導(dǎo)致當(dāng)前的線(xiàn)程等待,直到其他線(xiàn)程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 方法,或者其他某個(gè)線(xiàn)程中斷當(dāng)前線(xiàn)程,或者已超過(guò)某個(gè)實(shí)際時(shí)間量。
【Java線(xiàn)程同步的方法】相關(guān)文章:
Java多線(xiàn)程的實(shí)現(xiàn)方式03-20
Java枚舉的常用方法03-16
JAVA認(rèn)證開(kāi)源技術(shù):關(guān)于Java的對(duì)象equals方法03-04
Java中日期的處理方法03-09
sun認(rèn)證考試經(jīng)驗(yàn):多線(xiàn)程的幾種實(shí)現(xiàn)方法詳解01-22
Java數(shù)組操作方法大全03-04