我們在寫一個單例模式的管理類時都會這樣寫
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必須在此之后劝篷,不符合實(shí)際
*/
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华望,會管理自己的方法蕊蝗,所以不受上面的影響。