Java多线程(2)—线程同步
介紹了線程的基本概念和方法,終于進入到上一章中介紹的取款問題了。回顧下在支付寶和微信上做了綁定卡之后,查詢為3000,此時在支付寶和微信的均取出2000,此時銀行卡變成了-1000
?那上述取款如何實現呢?
package blog;public class TestAccount {public static void main(String[] args) {Account account = new Account();//多線程對象User u_weixin = new User(account, 2000);User u_zhifubao = new User(account, 2000);Thread weixin = new Thread(u_weixin,"微信賬戶");Thread zhifubao = new Thread(u_zhifubao,"支付寶賬戶");weixin.start();zhifubao.start();} }class Account{public static int money = 3000;//全局變量,共享數據public void takeMoney(int m) {String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,賬戶金額不足:"+money);}else {System.out.println(name + "操作,賬戶原有金額:"+money);System.out.println(name + "操作,取款金額:" + m);money = money - m;System.out.println(name + "操作,取款后的余額:" + money);}} }class User implements Runnable{Account account;int money;public User(Account account,int money) {// TODO Auto-generated constructor stubthis.account = account;this.money = money;}@Overridepublic void run() {// TODO Auto-generated method stubaccount.takeMoney(money);} }查看輸出結果
多線程調用方法時,存在上述問題。線程共享資源時,一個線程在執行方法沒有完畢時,另一個線程開始執行這個方法,導致共享數據出錯。那如何解決,自然就是讓一個線程先執行完成,在執行過程中拒絕其他線程參與執行。就是一個線程一個線程的依次完成執行。
1、方法加入synchronized同步鎖
通過在方法上加入關鍵字synchronized來處理。public?synchronized void takeMoney();因此將上述代碼中的takeMoney進行改造如下:
class Account{public static int money = 3000;public synchronized void takeMoney(int m) {String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,賬戶金額不足:"+money);}else {System.out.println(name + "操作,賬戶原有金額:"+money);System.out.println(name + "操作,取款金額:" + m);money = money - m;System.out.println(name + "操作,取款后的余額:" + money);}} }此時查看輸出結果如下:
?
注意:在普通方法上加同步鎖synchronized,鎖的是整個對象,不是某一個方法。如何理解這句話呢,我們將上述的方法進行改造。
1.將takeMoney復制一份命名為takeMoney1
2.將run中加入線程名稱判斷
package blog;public class TestAccount {public static void main(String[] args) {Account account = new Account();//多線程對象User u_weixin = new User(account, 2000);User u_zhifubao = new User(account, 2000);Thread weixin = new Thread(u_weixin,"微信賬戶");Thread zhifubao = new Thread(u_zhifubao,"支付寶賬戶");weixin.start();zhifubao.start();} }class Account{public static int money = 3000;public synchronized void takeMoney(int m) {String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,賬戶金額不足:"+money);}else {System.out.println(name + "操作,賬戶原有金額:"+money);System.out.println(name + "操作,取款金額:" + m);money = money - m;System.out.println(name + "操作,取款后的余額:" + money);}}public synchronized void takeMoney1(int m) {String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,賬戶金額不足:"+money);}else {System.out.println(name + "操作,賬戶原有金額:"+money);System.out.println(name + "操作,取款金額:" + m);money = money - m;System.out.println(name + "操作,取款后的余額:" + money);}}}class User implements Runnable{Account account;int money;public User(Account account,int money) {// TODO Auto-generated constructor stubthis.account = account;this.money = money;}@Overridepublic void run() {// TODO Auto-generated method stub // account.takeMoney(money);if (Thread.currentThread().getName() == "微信") {account.takeMoney(money);}else {account.takeMoney1(money);}} }輸出結果:
?發現輸出結果依然能正確輸出,這就是所謂的鎖住的是對象,因為我們定義了一個賬戶對象account。作為對比,新建兩個對象,則輸出結果如下所示:
綜上所述,所以說synchronized鎖住的是對象方法。不同的對象是不同的鎖,因此線程使用不同對象調用此方法依然有資源共享的問題。
//將Account中的takeMoney進行如下改造public static synchronized void takeMoney2(int m) {String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,賬戶金額不足:"+money);}else {System.out.println(name + "操作,賬戶原有金額:"+money);System.out.println(name + "操作,取款金額:" + m);money = money - m;System.out.println(name + "操作,取款后的余額:" + money);}}?將User中的方法調整如下
class User implements Runnable{Account account;int money;public User(Account account,int money) {// TODO Auto-generated constructor stubthis.account = account;this.money = money;}@Overridepublic void run() {account.takeMoney2(money);} }此時查看輸出結果
?
同static屬性和方法是共享的一樣,這里加入static synchronized 表示為類的屬性/方法。
2.代碼塊加入同步鎖
新增一個takeMoney4方法,并在代碼塊加入同步鎖synchronized
package blog;public class TestAccount {public static void main(String[] args) {Account account = new Account();Account account1 = new Account();//多線程對象User u_weixin = new User(account, 2000);User u_zhifubao = new User(account1, 2000);Thread weixin = new Thread(u_weixin,"微信賬戶");Thread zhifubao = new Thread(u_zhifubao,"支付寶賬戶");weixin.start();zhifubao.start();} }class Account{public static int money = 3000;public synchronized void takeMoney(int m) {String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,賬戶金額不足:"+money);}else {System.out.println(name + "操作,賬戶原有金額:"+money);System.out.println(name + "操作,取款金額:" + m);money = money - m;System.out.println(name + "操作,取款后的余額:" + money);}}/*** 靜態方法加synchronized,對所有對象都是同一個鎖* @param m*/public static synchronized void takeMoney2(int m) {String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,賬戶金額不足:"+money);}else {System.out.println(name + "操作,賬戶原有金額:"+money);System.out.println(name + "操作,取款金額:" + m);money = money - m;System.out.println(name + "操作,取款后的余額:" + money);}}public void takeMoney3(int m) {synchronized(this){//表示當前對象的代碼被加入了synchronized同步鎖,this表示當前對象String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,賬戶金額不足:"+money);}else {System.out.println(name + "操作,賬戶原有金額:"+money);System.out.println(name + "操作,取款金額:" + m);money = money - m;System.out.println(name + "操作,取款后的余額:" + money);}}}public void takeMoney4(int m) {synchronized(this){//表示當前對象的代碼被加入了synchronized同步鎖,this表示當前對象String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,賬戶金額不足:"+money);}else {System.out.println(name + "操作,賬戶原有金額:"+money);System.out.println(name + "操作,取款金額:" + m);money = money - m;System.out.println(name + "操作,取款后的余額:" + money);}}}}class User implements Runnable{Account account;int money;public User(Account account,int money) {// TODO Auto-generated constructor stubthis.account = account;this.money = money;}@Overridepublic void run() {// TODO Auto-generated method stub // account.takeMoney(money);if (Thread.currentThread().getName() == "微信") {account.takeMoney3(money);}else {account.takeMoney4(money);}// account.takeMoney2(money);} }依然是用的是兩個對象進行調用,輸出結果如下:
?
那如果使用的是一個對象呢?
//多線程對象User u_weixin = new User(account, 2000);User u_zhifubao = new User(account, 2000);輸出如下:
這里的輸出結果和使用方法同步鎖一樣,存在不同的對象出現共享資源有限錯誤的情況。那同一個對象加入相同的鎖,不同的對象加入不同的鎖如何實現呢,可以通過對方法傳入的對象加入synchronized同步鎖,如下所示:
public void takeMoney5(int m,Account a) {synchronized(a){//表示當前對象的代碼被加入了synchronized同步鎖,this表示當前對象String name = Thread.currentThread().getName();if (m > money) {System.out.println(name + "操作,賬戶金額不足:"+money);}else {System.out.println(name + "操作,賬戶原有金額:"+money);System.out.println(name + "操作,取款金額:" + m);money = money - m;System.out.println(name + "操作,取款后的余額:" + money);}}} class User implements Runnable{Account account;int money;public User(Account account,int money) {// TODO Auto-generated constructor stubthis.account = account;this.money = money;}@Overridepublic void run() { account.takeMoney5(money,account);} }如果是相同的對象,則輸出:
如果是不同的對象,則輸出:
?
因此可有如下結論:
?
總結
以上是生活随笔為你收集整理的Java多线程(2)—线程同步的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java多线程(1)—线程初探
- 下一篇: Java多线程(3)—生产者/消费者