簡體   English   中英

同步是否保留鎖定

[英]Does Synchronized retain lock

考慮一下代碼:

class Account {
  private int balance=50;
  public int getBalance(){
    return balance;
    }
    public void withdraw(int amt){
        balance=balance-amt;
        }
    }
public class AccountBalance implements Runnable {

    private Account acc=new Account();

    public static void main(String[] args) {
        AccountBalance accBal=new AccountBalance();
        Thread one=new Thread(accBal);
        Thread two=new Thread(accBal);
        one.setName("Thread One");
        two.setName("thread Two");
        one.start();
        two.start();
    }
    public void run(){
        for(int i=0;i<5;i++){
            makeWithdrawal(10);
        }
    }
    public synchronized void makeWithdrawal(int amount){
        if(acc.getBalance()>=amount){
            System.out.println(Thread.currentThread().getName()+" is going to withdraw "+acc.getBalance());
        try{
            Thread.sleep(500);
        }
        catch(InterruptedException ie){}
        acc.withdraw(amount);               //line 1
        System.out.println(Thread.currentThread().getName()+" completes the withdrawal");
        }
        else {
            System.out.println("Not enough in account for "+Thread.currentThread().getName()+" to withdraw "+acc.getBalance());
        }
    }
}

1)假設線程弗雷德進入一個同步塊並獲得對象accBal的鎖,然后在中間線程弗雷德的某個地方調用另一個未同步的方法(第1行) ,那么線程不釋放該鎖為什么? 如果線程從同步中退出,那么它應該釋放鎖,或者直到同步塊之前都需要鎖。

2)假設我還有一個方法,例如changeAccount ,它不同步,然后有一個新的線程,即具有相同對象accBal的 線程3 ,將進入該方法,並且可以更改變量余額,這違反了我們的同步代碼。

Java是否提供了任何規定,即使存在非同步代碼並且線程在對象上具有鎖,然后另一個線程也不應輸入具有相同對象的非同步代碼,這意味着一旦線程獲取了鎖除非釋放鎖,否則沒有線程將對該對象起作用。

  1. 該線程雖然從另一個方法執行代碼,但仍在執行原始的同步方法。 這種其他方法執行只是原始同步方法執行的一部分。

  2. 沒錯,任何線程任何時間都可以更改不受保護的值。

  3. 還有其他方法可以執行互斥(例如使用CountDownLatch),但是如果不完全同步關鍵部分,則可能會遇到多線程內存問題,例如過時的值。

1)假設線程弗雷德進入一個同步塊並獲得對象accBal的鎖,然后在中間線程弗雷德的某個地方調用另一個未同步的方法(第1行),那么線程不釋放該鎖為什么?

考慮以下代碼

synchronized (accBal) {
    method()
}
// this line has to be reached before the lock on accBal is released

調用method()時,它不會退出同步塊,同步塊被“推”到堆棧上,並保留到對method()的調用返回(退出)時。 因此,在調用method()期間不會釋放鎖定。

2)假設我還有一個方法,例如changeAccount,它不同步,然后有一個新的線程,即具有相同對象accBal的線程3,將進入該方法,並且可以更改變量余額,這違反了我們的同步代碼。

正確。 這將破壞同步,並且行為難以預測,並且線程之間任何數據更改的可見性都容易出現數據爭奪和底層優化的副作用。 因此,重要的是每個人都應尊重同步塊。

3)Java是否提供了任何規定,即使存在非同步代碼並且線程在對象上具有鎖,然后另一個線程也不應輸入具有相同對象的非同步代碼,這意味着一旦采取了鎖除非鎖被釋放,否則沒有線程將對該對象起作用。

在Java中,所有悲觀的鎖定形式都要求每個線程相互配合並檢查鎖定。 理由是執行並發檢查需要一定的成本,並且大多數代碼不需要這些開銷。

  1. 同步塊僅在退出時釋放鎖。 確實沒有充分的理由說明這種情況,並且如果您的邏輯能夠處理隨着方法的進展而變化的成員變量,那么您就不受約束。 使用ReadWrite鎖(可能是ReentrantReadWriteLock)並研究它們提供的模式。
  2. 如果您有時使用鎖訪問成員變量,有時不使用鎖,則可能根本不應該使用它們。 當然,像SONAR這樣的產品會在此圖案上帶有一個紅色大標志。 同樣,您可能希望使用使用ReadWriteLock的細粒度方法。

否。如果您有一種方法可以訪問應受保護的數據,則該方法(或其中的關鍵代碼)應該是同步的(在同一對象上)。 如果您使該方法不同步,則意味着程序員認為它訪問的數據不需要保護。

您可以使用其他鎖定方法,但是沒有什么可以使Java鎖定成為程序員認為不值得進行的鎖定。 鎖定會降低性能,因此不受保護的代碼(程序員認為安全的代碼)不應自動受到保護。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM