多線程安全 synchronized使用

我們在寫一個單例模式的管理類時都會這樣寫

public class ConfigManager {
    private static ConfigManager instance;
    private ConfigManager(){}
    public static synchronized ConfigManager getInstance(){
        if(instance==null){
            instance=new ConfigManager();
        }
        return instance;
    }
    public static ConfigManager getInstanceUseDoubleLock(){
        if(instance==null){
            synchronized (ConfigManager.class){
                if(instance==null){
                    instance=new ConfigManager();
                }
            }
        }
        return instance;
    }
}

上面的線程安全有兩種寫法,一個是在方法上加synchronized,一個是在代碼塊中加上synchronized,這兩個有方法加上synchronized有什么用,又有什么區(qū)別呢?
1.一個類如下:

public class UserManager {
    private User user;
    public UserManager(User user) {
        this.user = user;
    }
    public void updateUser(User newUser){
        user.setName(newUser.getName());
        user.setGender(newUser.getGender());
    }
}

2.創(chuàng)建一個User類

public class User {
    private String name;
    private String gender;
    public User() {}
    public User(String name, String gender) {
        this.name = name;
        this.gender = gender;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    @Override
    public String toString() {
        return "User{" + "name='" + name + '\'' + ", gender='" + gender + '\'' + '}';
    }
}

3.開啟兩個線程

 private User user;
 private UserManager userManager;
 user = new User();
 userManager = new UserManager(user);
//線程一
        new Thread(new Runnable() {
            @Override
            public void run() {
                User user1=new User("Tom","男");
                userManager.updateUser(user1);
            }
        }).start();
        //線程二
        new Thread(new Runnable() {
            @Override
            public void run() {
                User user2=new User("鳳姐","女");
                userManager.updateUser(user2);
            }
        }).start();
      Log.e("user----",user.toString());   
        

4.結(jié)果:
線程一:name="Tom";
線程二:name="鳳姐";
線程二:gender="女";
線程一:gender="男";
結(jié)果:name="鳳姐",gender="男"

結(jié)果數(shù)據(jù)混亂了

使用synchronized解決方法

 public synchronized void updateUser(User newUser){
        user.setName(newUser.getName());
        user.setGender(newUser.getGender());
    }

有一個場景:新增一個printUser方法

public synchronized void updateUser(User newUser){
        user.setName(newUser.getName());
        user.setGender(newUser.getGender());
    }
public synchronized void printUser(){
        Log.e("UserManager--","name:"+user.getName()+"--gender:"+user.getGender());
    }

updateUser和printUser方法上都加上鎖synchronized,這個時候updateUser方法調(diào)用時,線程中printUser方法不會調(diào)用的,可以確保我的信息寫入完之后,我才能讀取,

現(xiàn)在有一個場景需求:我想新加一個方法,兩個方法同時進(jìn)行,互不影響

如下:

public class UserManager {
    private User user;
    private final Object monitor2=new Object();
    public UserManager(User user) {
        this.user = user;
    }
    public synchronized void updateUser(User newUser){
        user.setName(newUser.getName());
        user.setGender(newUser.getGender());
    }
    public synchronized void printUser(){
        Log.e("UserManager--","name:"+user.getName()+"--gender:"+user.getGender());
    }
    /**
     * 現(xiàn)在新增的其他方法也加上鎖synchronized,這樣會導(dǎo)致其他必須在上面的updateUser調(diào)用完畢才能執(zhí)行,
     * 這樣我想調(diào)用otherMethod必須在此之后,不符合實際
     */
    public void otherMethod(){
        synchronized (monitor2){
            Log.e("UserManager--","同時調(diào)用第二個方法");
        }
    }
}

synchronized在兩個方法加入的位置不一樣,有什么區(qū)別呢?

updateUser()和printUser()方法在方法上加上鎖,此時它們有系統(tǒng)提供的默認(rèn)管理者monitor在管理,當(dāng)updateUser()進(jìn)去線程管理后,printUser()是不能進(jìn)去了,所以這個方法不調(diào)用, 而otherMethod()方法在代碼塊里添加一個自己創(chuàng)建的monitor2,會管理自己的方法,所以不受上面的影響。

注意:線程不安全是因為數(shù)據(jù)讀取中,進(jìn)行write寫入或者write寫入中有讀取,如果兩個線程都是讀取不會存在線程安全問題
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,621評論 1 32
  • 1、Synchronized關(guān)鍵字 1、方法中的變量不存在非線程安全問題,都是線程安全的。 2、兩個線程訪問同一個...
    AI喬治閱讀 1,547評論 1 7
  • 一、基礎(chǔ)知識:1、JVM、JRE和JDK的區(qū)別:JVM(Java Virtual Machine):java虛擬機(jī)...
    殺小賊閱讀 2,553評論 0 4
  • 本文主要講了java中多線程的使用方法、線程同步、線程數(shù)據(jù)傳遞、線程狀態(tài)及相應(yīng)的一些線程函數(shù)用法、概述等。 首先講...
    李欣陽閱讀 2,593評論 1 15
  • 母親坐在矮板凳上 花生一粒一粒落在笸籮 生活啊,需要點油來滋潤 何況 我得在大地生根
    黃燙閱讀 265評論 0 0

友情鏈接更多精彩內(nèi)容