gpt4 book ai didi

java - 从单例类返回的对象引用是线程安全的吗?

转载 作者:行者123 更新时间:2023-11-29 09:29:34 25 4
gpt4 key购买 nike

我想从单例类返回一个对象,该对象被许多线程使用,单例类中还有两个方法。返回该对象引用是否安全?请看我的样本

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;
}
}

最佳答案

根据 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 block 之外的访问都不是线程安全的。

注意:线程之间没有协调,一个线程可能在另一个线程开始之前完成。此外,递增计数器比打印到控制台要快得多,因此您应该看到计数器跳了很多,实际上它可能从 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);
}
}

关于java - 从单例类返回的对象引用是线程安全的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27666031/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com