我想从单例类返回一个对象,该对象由多个线程使用,并且还在单例类中使用两个方法。返回该对象引用是否安全?请参阅我的样本
public class MainClass {
public static void main(String[] args) {
Thread t = new Thread() {
public void run() {
MyObject rv = Singleton.getInstance().get();
for (int i = 0; i < 100; i++) {
System.out.println("THREAD 0 : " + rv.getCount());
}
}
};
t.start();
Thread t1 = new Thread() {
public void run() {
for (int i = 0; i < 100; i++) {
Singleton.getInstance().update();
}
}
};
t1.start();
}
}
和
import java.util.HashMap;
public class Singleton {
private static Singleton instance;
private Singleton() {
MyObject rv = new MyObject(1, 1);
hashmap.put(1, rv);
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
private final HashMap<Integer, MyObject> hashmap = new HashMap<>();
public MyObject get() {
return hashmap.get(1);
}
public void update() {
hashmap.get(1).setCount(hashmap.get(1).getCount() + 1);
}
}
和
public class MyObject {
int count;
int id;
MyObject(int id, int count) {
this.id = id;
this.count = count;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
答案 0 :(得分:0)
根据MyObject的使用方式,您还需要保护对字段的访问权。
public enum Singleton {
INSTANCE;
public static Singleton getInstance() {
return INSTANCE;
}
private final Map<Integer, MyObject> map = new HashMap<>();
public synchronized int getCount(int key) {
MyObject mo = map.get(key);
if (mo == null)
return 1;
return mo.getCount();
}
public synchronized void update(int key) {
MyObject mo = map.get(key);
if (mo == null)
map.put(key, mo = new MyObject(1, 1));
mo.incrementCount();
}
}
在MyObject类中,您将添加一个方法
public void incrementCount() {
count++;
}
注意:由于您无法直接访问基础MyObject,因此无需添加其他同步。
对象的引用是线程安全的,但synchronized
块之外的访问都不是线程安全的。
注意:线程之间没有协调,一个可以在另一个开始之前完成。增加一个计数器比打印到控制台要快得多,所以你应该看到计数器跳了很多,实际上它可能会从0跳到100,相隔一行。 事实上,你把它放在了错误的地方,你可以这样做。
public enum Singleton {
INSTANCE;
private Singleton() {
hashmap.put(1, new MyObject(1, 1));
}
public static Singleton getInstance() {
return INSTANCE;
}
private final Map<Integer, MyObject> hashmap = new HashMap<>();
public synchronized MyObject get() {
// safe is all you need to do is read one value.
return hashmap.get(1);
}
public synchronized void update() {
hashmap.get(1).setCount(hashmap.get(1).getCount() + 1);
}
}
甚至更简单
public enum Singleton {
INSTANCE;
private final MyObject myObj = new MyObject(1, 1);
public static Singleton getInstance() {
return INSTANCE;
}
public synchronized MyObject get() {
// safe is all you need to do is read one value.
return myObj;
}
public synchronized void update() {
myObject.setCount(myObject.getCount() + 1);
}
}
答案 1 :(得分:-1)
您必须使Object线程安全,因为此类的实例由不同的线程使用(请注意同步的方法:
public class MyObject {
int count;
int id;
MyObject(int id, int count) {
this.id = id;
this.count = count;
}
public synchronized int getCount() {
return count;
}
public synchronized void setCount(int count) {
this.count = count;
}
public synchronized int getId() {
return id;
}
public synchronized void setId(int id) {
this.id = id;
}
}