簡體   English   中英

如何在Java中同步或鎖定變量?

[英]How to synchronize or lock upon variables in Java?

讓我用這個小而簡單的樣本:

class Sample {
    private String msg = null;

    public void newmsg(String x){
        msg = x;
    }

    public String getmsg(){
        String temp = msg;
        msg = null;
        return temp;
    }
}

我們假設函數newmsg()由我無權訪問的其他線程調用。

我想使用synchonize方法來保證字符串msg每次僅由一個函數使用。 換句話說,函數newmsg()不能與getmsg()同時運行。

這很簡單:

class Sample {
    private String message = null;
    private final Object lock = new Object();

    public void newMessage(String x) {
        synchronized (lock) {
            message = x;
        }
    }

    public String getMessage() {
        synchronized (lock) {
            String temp = message;
            message = null;
            return temp;
        }
    }
}

請注意,我也沒有讓自己的同步方法或同步this 我堅信只有你的代碼可以訪問的對象才能獲得鎖,這是個好主意,除非你故意暴露鎖。 這樣可以更容易地讓自己放心,沒有其他任何東西會以與代碼不同的順序獲取鎖定等。

對於此功能,最好不要使用鎖。 嘗試AtomicReference。

public class Sample {
    private final AtomicReference<String> msg = new AtomicReference<String>();

    public void setMsg(String x) {
        msg.set(x);
    }

    public String getMsg() {
        return msg.getAndSet(null);
    }
}

不需要鎖,代碼更簡單恕我直言。 在任何情況下,它都使用標准結構,它可以滿足您的需求。

從Java 1.5開始,考慮java.util.concurrent包總是一個好主意。 它們現在是java中最先進的鎖定機制。 同步機制比java.util.concurrent類更重要。

該示例看起來像這樣:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Sample {

    private final Lock lock = new ReentrantLock();

    private String message = null;

    public void newmsg(String msg) {
        lock.lock();
        try {
            message = msg;
        } finally {
            lock.unlock();
        }
    }

    public String getmsg() {
        lock.lock();
        try {
            String temp = message;
            message = null;
            return temp;
        } finally {
            lock.unlock();
        }
    }
}

在這個簡單的示例中,您可以在兩個方法簽名中將synchronized作為修飾符放在public之后。

更復雜的場景需要其他東西。

使用synchronized關鍵字。

class sample {
    private String msg=null;

    public synchronized void newmsg(String x){
        msg=x;
    }

    public synchronized string getmsg(){
        String temp=msg;
        msg=null;
        return msg;
    }
}

在方法上使用synchronized關鍵字將要求線程獲取對sample實例的鎖定。 因此,如果任何一個線程都在newmsg() ,那么即使它試圖調用getmsg() ,也沒有其他線程能夠對sample實例進行鎖定。

另一方面,如果您的方法執行長時間運行操作,使用synchronized方法可能會成為瓶頸 - 所有線程,即使他們想要調用該對象中可能交錯的其他方法,仍然需要等待。

IMO,在你的簡單例子中,可以使用synchronized方法,因為你實際上有兩個不應該交錯的方法。 但是,在不同的情況下,讓一個鎖定對象同步更有意義,如Joh Skeet的回答所示。

如果在另一個場合你正在同步一個Collection而不是一個String,也許你正在迭代這個集合,並擔心它會發生變異,Java 5提供:

暫無
暫無

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

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