本篇文章主要透過實例介紹了Java執行緒:執行緒的同步-同步方法,需要的朋友可以參考下
執行緒的同步是保證多執行緒安全存取競爭資源的一種手段。
執行緒的同步是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); 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; } /** * 业务方法 * @param x 添加x万元 */ public synchronized void oper(int x) { try { Thread.sleep(10L); this.cash += x; System.out.println(Thread.currentThread().getName() + "运行结束,增加“" + x + "”,当前用户账户余额为:" + cash); Thread.sleep(10L); } catch (InterruptedException e) { e.printStackTrace(); } } @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
反面教材,不同步的情況,也就是去掉oper(int x)方法的synchronized修飾符,然後運行程序,結果如下:
线程A运行结束,增加“20”,当前用户账户余额为:61 线程D运行结束,增加“-30”,当前用户账户余额为:63 线程B运行结束,增加“-60”,当前用户账户余额为:3 线程F运行结束,增加“21”,当前用户账户余额为:61 线程E运行结束,增加“32”,当前用户账户余额为:93 线程C运行结束,增加“-80”,当前用户账户余额为:61
很顯然,上面的結果是錯誤的,導致錯誤的原因是多個線程並發訪問了競爭資源u,並對u的屬性做了改動。
可見同步的重要性。
注意:
透過前文可知,當線程退出同步方法時會釋放掉方法所屬物件的鎖定,但也應該注意的是,同步方法中還可以使用特定的方法對執行緒進行調度。這些方法來自於java.lang.Object類別。
void notify() 唤醒在此对象监视器上等待的单个线程。 void notifyAll() 唤醒在此对象监视器上等待的所有线程。 void wait() 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。 void wait(long timeout) 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。 void wait(long timeout, int nanos) 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量
結合以上方法,處理多執行緒同步與互斥問題非常重要,著名的生產者-消費者例子就是一個經典的例子,任何語言多執行緒必學的例子。
以上是關於Java執行緒同步與同步方法的詳細解的詳細內容。更多資訊請關注PHP中文網其他相關文章!