程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java應用synchronized潤飾辦法來同步線程的實例演示

Java應用synchronized潤飾辦法來同步線程的實例演示

編輯:關於JAVA

Java應用synchronized潤飾辦法來同步線程的實例演示。本站提示廣大學習愛好者:(Java應用synchronized潤飾辦法來同步線程的實例演示)文章只能為提供參考,不一定能成為您想要的結果。以下是Java應用synchronized潤飾辦法來同步線程的實例演示正文


Java中可使用症結字synchronized停止線程同步掌握,完成症結資本次序拜訪,防止因為多線程並發履行招致的數據紛歧致性等成績。synchronized的道理是對象監督器(鎖),只要獲得到監督器的線程能力持續履行,不然線程會期待獲得監督器。Java中每一個對象或許類都有一把鎖與之相干聯,關於對象來講,監督的是這個對象的實例變量,關於類來講,監督的是類變量(一個類自己是類Class的對象,所以與類聯系關系的鎖也是對象鎖)。synchronized症結字應用方法有兩種:synchronized辦法和synchronized塊。這兩種監督區域都和一個引入對象相干聯,當達到這個監督區域時,JVM就會鎖住這個援用對象,當分開時會釋放這個援用對象上的鎖(有異常加入時,JVM會釋放鎖)。對象鎖是JVM外部機制,只須要編寫同步辦法或許同步塊便可,操作監督區域時JVM會主動獲得鎖或許釋放鎖。

示例1

先來看第一個示例,在java中,統一個對象的臨界區,在統一時光只要一個許可被拜訪(都長短靜態的synchronized辦法):

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();
    }
  }
}

/*帳戶*/
class Account{
  private double balance;
  /*將傳入的數據加到余額balance中*/
  public synchronized void addAmount(double amount){
    double tmp = balance;
    try {
      Thread.sleep(10);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    tmp += amount;
    balance = tmp;
  }
  /*將傳入的數據從余額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;
  }
}

/*銀行*/
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);
    }
  }
}

/*公司*/
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);
    }
  }
}

你曾經開辟了一個銀行賬戶的模仿運用,它可以或許對余額停止充值和扣除。這個法式經由過程挪用100次addAmount()辦法對帳戶停止充值,每次存入1000;然後經由過程挪用100次subtractAmount()辦法對帳戶余額停止扣除,每次扣除1000;我們希冀帳戶的終究余額與起先余額相等,我們經由過程synchronized症結字完成了。

假如想檢查同享數據的並發拜訪成績,只須要將addAmount()和subtractAmount()辦法聲明中的synchronized症結字刪除便可。在沒有synchronized症結字的情形下,打印出來的余額值其實不分歧。假如屢次運轉這個法式,你將獲得分歧的成果。由於JVM其實不包管線程的履行次序,所以每次運轉的時刻,線程將以分歧的次序讀取而且修正帳戶的余額,形成終究成果也是紛歧樣的。

一個對象的辦法采取synchronized症結字停止聲明,只能被一個線程拜訪。假如線程A正在履行一個同步辦法syncMethodA(),線程B要履行這個對象的其他同步辦法syncMethodB(),線程B將被壅塞直到線程A拜訪完。但假如線程B拜訪的是統一個類的分歧對象,那末兩個線程都不會被壅塞。

示例2

演示統一個對象上的靜態synchronized辦法與非靜態synchronized辦法可以在統一時光點被多個線程拜訪的成績,驗證一下。

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();
    }
  }
}

/*帳戶*/
class Account{
  /*這裡改成靜態變量*/
  private static double balance = 0;
  /*將傳入的數據加到余額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;
  }
  /*將傳入的數據從余額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;
  }
}

/*銀行*/
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);
    }
  }
}

/*公司*/
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症結字潤飾。履行成果年夜家可以本身測試一下,每次履行都是紛歧樣的成果!

一些總結:

  • synchronized是經由過程軟件(JVM)完成的,簡略易用,即便在JDK5以後有了Lock,依然被普遍地應用。
  • synchronized現實上長短公正的,新來的線程有能夠立刻取得監督器,而在期待區中等待已久的線程能夠再次期待,不外這類搶占的方法可以預防饑餓。
  • synchronized只要鎖只與一個前提(能否獲得鎖)相干聯,不靈巧,後來Condition與Lock的聯合處理了這個成績。
  • 多線程競爭一個鎖時,其他未獲得鎖的線程只能一直的測驗考試取得鎖,而不克不及中止。高並發的情形下會招致機能降低。ReentrantLock的lockInterruptibly()辦法可以優先斟酌呼應中止。 一個線程期待時光太長,它可以中止本身,然後ReentrantLock呼應這個中止,不再讓這個線程持續期待。有了這個機制,應用ReentrantLock時就不會像synchronized那樣發生逝世鎖了。
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved