如果您运行此代码,可能会导致不可预知的结果,因为两个线程可以同时调用 newInstance 方法,两者都会将该entity
字段视为 null 并且都会创建new Entity
. 在这种情况下,这两个线程将具有此类的不同实例。
您的类中应该有一个静态私有字段 Entity 实体,而不是从地图中获取它。这就是为什么你应该使用同步。您可以像这样同步整个方法:
public synchronized static Entity newInstance(UUID entityId)
作为替代方案,您可以使用更好的双重检查锁定,但必须小心操作 - 请查看下面的评论。
至于这个类的线程安全还有另一件事——你正在使用的地图。它使类 Mutable,因为 Entity 对象的状态在映射更改时会更改。在这种情况下,Final 是不够的。您应该将地图存储在其他类中,例如 EntityManager。
我认为你的实体应该很简单,不应该对“我是独一无二的”这个问题感兴趣——这应该是别人的职责。所以这就是为什么我建议实体看起来像这样:
public class Entity {
private final UUID entityId;
public Entity(UUID entityId) {
this.entityId = entityId;
}
public UUID getEntityId() {
return entityId;
}
}
现在它是不可变的并且将保持这种状态,因为它的字段是最终的且不可变的。如果您想添加一些字段,请确保这些字段也是不可变的。
至于存储,我建议一些持有者类:
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class EntityHolder {
private static Map<UUID, Entity> entities;
private static volatile EntityHolder singleton;
public EntityHolder() {
entities = new ConcurrentHashMap<UUID, Entity>();
}
public Entity getEntity(final UUID id) {
return entities.get(id);
}
public boolean addEntity(final UUID id, final Entity entity) {
synchronized (entities) {
if (entities.containsKey(id)) {
return false;
} else {
entities.put(id, entity);
return true;
}
}
}
public void removeEntity(final UUID id) {
entities.remove(id);
}
public static EntityHolder getInstance() {
if (singleton == null) {
synchronized (EntityHolder.class) {
if (singleton == null) {
singleton = new EntityHolder();
}
}
}
return singleton;
}
}
这样,您就可以将其与所有其他类分开但可以访问。至于创建我会使用这样的创建者(工厂):
import java.util.UUID;
public class EntityCreator {
public static void createEntity(final UUID id) {
boolean entityAdded = EntityHolder.getInstance().addEntity(id, new Entity(id));
if (entityAdded) {
System.out.println("Entity added.");
} else {
System.out.println("Entity already exists.");
}
}
}