一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - Java使用synchronized修飾方法來同步線程的實例演示

Java使用synchronized修飾方法來同步線程的實例演示

2020-05-17 14:01柳哥 JAVA教程

synchronized下的方法控制多線程程序中的線程同步非常方便,這里就來看一下Java使用synchronized修飾方法來同步線程的實例演示,需要的朋友可以參考下

Java中可以使用關鍵字synchronized進行線程同步控制,實現(xiàn)關鍵資源順序訪問,避免由于多線程并發(fā)執(zhí)行導致的數(shù)據(jù)不一致性等問題。synchronized的原理是對象監(jiān)視器(鎖),只有獲取到監(jiān)視器的線程才能繼續(xù)執(zhí)行,否則線程會等待獲取監(jiān)視器。Java中每個對象或者類都有一把鎖與之相關聯(lián),對于對象來說,監(jiān)視的是這個對象的實例變量,對于類來說,監(jiān)視的是類變量(一個類本身是類Class的對象,所以與類關聯(lián)的鎖也是對象鎖)。synchronized關鍵字使用方式有兩種:synchronized方法和synchronized塊。這兩種監(jiān)視區(qū)域都和一個引入對象相關聯(lián),當?shù)竭_這個監(jiān)視區(qū)域時,JVM就會鎖住這個引用對象,當離開時會釋放這個引用對象上的鎖(有異常退出時,JVM會釋放鎖)。對象鎖是JVM內部機制,只需要編寫同步方法或者同步塊即可,操作監(jiān)視區(qū)域時JVM會自動獲取鎖或者釋放鎖。

示例1

先來看第一個示例,在java中,同一個對象的臨界區(qū),在同一時間只有一個允許被訪問(都是非靜態(tài)的synchronized方法):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package concurrency;
 
public class Main8 {
  public static void main(String[] args) {
    Account account = new Account();
    account.setBalance(1000);
    Company company = new Company(account);
    Thread companyThread = new Thread(company);
    Bank bank = new Bank(account);
    Thread bankThread = new Thread(bank);
    System.out.printf("Account : Initial Balance: %f\n", account.getBalance());
    companyThread.start();
    bankThread.start();
    try {
      //join()方法等待這兩個線程運行完成
      companyThread.join();
      bankThread.join();
      System.out.printf("Account : Final Balance: %f\n", account.getBalance());
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}
?
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
/*帳戶*/
class Account{
  private double balance;
  /*將傳入的數(shù)據(jù)加到余額balance中*/
  public synchronized void addAmount(double amount){
    double tmp = balance;
    try {
      Thread.sleep(10);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    tmp += amount;
    balance = tmp;
  }
  /*將傳入的數(shù)據(jù)從余額balance中扣除*/
  public synchronized void subtractAmount(double amount){
    double tmp = balance;
    try {
      Thread.sleep(10);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    tmp -= amount;
    balance = tmp;
  }
  public double getBalance() {
    return balance;
  }
  public void setBalance(double balance) {
    this.balance = balance;
  }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
/*銀行*/
class Bank implements Runnable{
  private Account account;
  public Bank(Account account){
    this.account = account;
  }
  @Override
  public void run() {
    for (int i = 0; i < 100; i++) {
      account.subtractAmount(1000);
    }
  }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
/*公司*/
class Company implements Runnable{
  private Account account;
  public Company(Account account){
    this.account = account;
  }
  @Override
  public void run() {
    for (int i = 0; i < 100; i++) {
      account.addAmount(1000);
    }
  }
}

你已經(jīng)開發(fā)了一個銀行賬戶的模擬應用,它能夠對余額進行充值和扣除。這個程序通過調用100次addAmount()方法對帳戶進行充值,每次存入1000;然后通過調用100次subtractAmount()方法對帳戶余額進行扣除,每次扣除1000;我們期望帳戶的最終余額與起初余額相等,我們通過synchronized關鍵字實現(xiàn)了。

如果想查看共享數(shù)據(jù)的并發(fā)訪問問題,只需要將addAmount()和subtractAmount()方法聲明中的synchronized關鍵字刪除即可。在沒有synchronized關鍵字的情況下,打印出來的余額值并不一致。如果多次運行這個程序,你將獲取不同的結果。因為JVM并不保證線程的執(zhí)行順序,所以每次運行的時候,線程將以不同的順序讀取并且修改帳戶的余額,造成最終結果也是不一樣的。

一個對象的方法采用synchronized關鍵字進行聲明,只能被一個線程訪問。如果線程A正在執(zhí)行一個同步方法syncMethodA(),線程B要執(zhí)行這個對象的其他同步方法syncMethodB(),線程B將被阻塞直到線程A訪問完。但如果線程B訪問的是同一個類的不同對象,那么兩個線程都不會被阻塞。

示例2

演示同一個對象上的靜態(tài)synchronized方法與非靜態(tài)synchronized方法可以在同一時間點被多個線程訪問的問題,驗證一下。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package concurrency;
 
public class Main8 {
  public static void main(String[] args) {
    Account account = new Account();
    account.setBalance(1000);
    Company company = new Company(account);
    Thread companyThread = new Thread(company);
    Bank bank = new Bank(account);
    Thread bankThread = new Thread(bank);
    System.out.printf("Account : Initial Balance: %f\n", account.getBalance());
    companyThread.start();
    bankThread.start();
    try {
      //join()方法等待這兩個線程運行完成
      companyThread.join();
      bankThread.join();
      System.out.printf("Account : Final Balance: %f\n", account.getBalance());
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}
?
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
/*帳戶*/
class Account{
  /*這里改為靜態(tài)變量*/
  private static double balance = 0;
  /*將傳入的數(shù)據(jù)加到余額balance中,注意是用static修飾過的*/
  public static synchronized void addAmount(double amount){
    double tmp = balance;
    try {
      Thread.sleep(10);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    tmp += amount;
    balance = tmp;
  }
  /*將傳入的數(shù)據(jù)從余額balance中扣除*/
  public synchronized void subtractAmount(double amount){
    double tmp = balance;
    try {
      Thread.sleep(10);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    tmp -= amount;
    balance = tmp;
  }
  public double getBalance() {
    return balance;
  }
  public void setBalance(double balance) {
    this.balance = balance;
  }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
/*銀行*/
class Bank implements Runnable{
  private Account account;
  public Bank(Account account){
    this.account = account;
  }
  @Override
  public void run() {
    for (int i = 0; i < 100; i++) {
      account.subtractAmount(1000);
    }
  }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
/*公司*/
class Company implements Runnable{
  private Account account;
  public Company(Account account){
    this.account = account;
  }
  @Override
  public void run() {
    for (int i = 0; i < 100; i++) {
      account.addAmount(1000);
    }
  }
}

我只是把上個例子中的,balance加了static關鍵字修改,addAmount()方法也可以static關鍵字修飾。執(zhí)行結果大家可以自己測試一下,每次執(zhí)行都是不一樣的結果!

一些總結:

  • synchronized是通過軟件(JVM)實現(xiàn)的,簡單易用,即使在JDK5之后有了Lock,仍然被廣泛地使用。
  • synchronized實際上是非公平的,新來的線程有可能立即獲得監(jiān)視器,而在等待區(qū)中等候已久的線程可能再次等待,不過這種搶占的方式可以預防饑餓。
  • synchronized只有鎖只與一個條件(是否獲取鎖)相關聯(lián),不靈活,后來Condition與Lock的結合解決了這個問題。
  • 多線程競爭一個鎖時,其余未得到鎖的線程只能不停的嘗試獲得鎖,而不能中斷。高并發(fā)的情況下會導致性能下降。ReentrantLock的lockInterruptibly()方法可以優(yōu)先考慮響應中斷。 一個線程等待時間過長,它可以中斷自己,然后ReentrantLock響應這個中斷,不再讓這個線程繼續(xù)等待。有了這個機制,使用ReentrantLock時就不會像synchronized那樣產(chǎn)生死鎖了。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 香蕉精品国产高清自在自线 | 国色天香论坛社区在线视频 | 双性np玩烂了np欲之国的太子 | 国色天香论坛社区在线视频 | 操娇妻 | bl动漫在线观看 | 日本欧美大码a在线视频播放 | 变态女王麻麻小说在线阅读 | 毛片一级毛片 | 精品一区二区三区波多野结衣 | 欧美69巨大jizzsex | 黑人巨大vs北条麻妃在线 | caopo视频进入离开 | 日韩亚洲欧美一区二区三区 | 免费视频精品一区二区三区 | 青青成人福利国产在线视频 | 欧美一区二区三区高清不卡tv | 久久99精国产一区二区三区四区 | 成人在线观看免费视频 | 亚洲国产精品久久无套麻豆 | 91东航翘臀女神在线播放 | 91桃花 | 男人把大ji巴放进男人免费视频 | 无码国产成人午夜在线观看不卡 | 欧美一级特黄特色大片免费 | 欧美日韩一区二区综合 | 成年男女免费大片在线观看 | 国产精彩对白综合视频 | 思思玖玖玖在线精品视频 | 好大好硬好湿好紧h | 黄+色+性+人免费 | 国产高清在线不卡 | 亚洲国产精品日本无码网站 | 日韩一区视频在线 | 车上小婕子系列辣文小说 | 俄罗斯处女 | 久久久无码精品亚洲A片软件 | 日本高清在线看 | 亚洲精品视频在线免费 | 亚洲国产第一区二区香蕉日日 | 国产免费美女视频 |