关于jivedon的并发问题,请板桥老师指点。

09-05-13 xmuzyu
    

jivedon中获取对象是在dao的装饰器中获取的,ForumDaoCache代码如下:
Forum forum = (Forum) containerUtil.getModelFromCache(forumId, Forum.class);
if (forum == null){
forum = super.getForum(forumId);
containerUtil.addModeltoCache(forumId, forum);
}
return forum;

这个时候加有两个并发用户同时调用ForumDaoCache的getForum方法,此时有可能两个线程都获得了一个不同的Forum对象,这个时候是最后的线程获取的对象会覆盖缓存中以前的值,而后在ForumDirector中判断forum.isEmbedded(),其实这个时候不同的线程已经有不同的对象,这个判断也就失去了意义了。

请banq老师指点,是我理解有误还是本来就有这个问题。我在项目中通过一个MonitorObject解决了这个问题,保证了并发线程获取全局唯一的对象实例。

    

banq
2009-05-13 20:13

这里面有一个性能和安全综合,是有可能出现你说的情况,但是出现两个Forum只是系统开始一瞬间,几率很小,正常情况,都是对缓存中的Forum读取,另外这还看看Forum是否是聚合根实体,如果不是,就当作是两个值对象,复制克隆也无非不可。

相反,如果为了避免这个情况,目前通过锁或其他控制总是会损失性能,再加上如果这个Forum获取出来只是读共享,可以忽略不计。

当然如果是需要缓存写,那也不会影响写,因为不可能在Forum创建的同一个线程中有业务写事件,这是不可能发生的。

如果不介意,可以谈谈你的MonitorObject是怎么实现的,这样做得很细致完美当然好。

xmuzyu
2009-05-13 20:35

>>相反,如果为了避免这个情况,目前通过锁或其他控制总是会损失性能,再加上如果这个Forum获取出来只是读共享,可以忽略不计。

呵呵,多谢老师解答。我的项目中因为要对获取的对象进行写操作,所以必须保证获得对象是唯一的。

我的办法是新建一个监视器对象MonitorObject:如下:

public class MonitorObject {

private Class<?> modelClass;

private Serializable key;

public Class<?> getModelClass() {
// TODO Auto-generated method stub
return modelClass;
}

public boolean needSynchroize(Class<PersonalPage> modelClass, String id) {

return this.modelClass.equals(modelClass) && this.key.equals(id);
}

public MonitorObject(Class<?> modelClass, Serializable key) {
super();
this.modelClass = modelClass;
this.key = key;
}

}

有一个ModelManager负责管理Model,ModelManager首先从缓存中获取对象,如果没有不是返回null,而是返回MonitorObject,这个MnitorObject负责检测并发线程想要获得的对象是否是同一个Model,而我判断是否是同一个Model就是简单的判断对应的class和model主键是否一致,如果一致就同步。

客户端代码:
Object model = modelManager.getModel(PersonalPage.class, owner.getId());


if (model instanceof PersonalPage) {
return (PersonalPage) model;
}
//如果缓存中没有对应的对象,那么就从数据库构建,然后放回缓存
PersonalPage page = null;
if (model instanceof MonitorObject) {
MonitorObject monitor = (MonitorObject) model;
if (monitor.needSynchroize(PersonalPage.class, owner.getId())) {
synchronized (PersonalPage.class) {
Object o = modelManager.getModel(PersonalPage.class, owner
.getId());
//fireGetEvent(event);
//Object o = event.getModel();
if (o instanceof PersonalPage) {
return (PersonalPage) o;
}

construct(page, owner);
modelManager.addModle(page.getId(), page);
}

}

}

return page;

ACoder
2009-05-13 20:45

我没有看过jdon的源代码
》》但是出现两个Forum只是系统开始一瞬间,几率很小,正常情况,都是对缓存中的Forum读取

我觉得这样的说法不负责任,不能因为概率小就不去维护。
其实只要在addModeltoCache的方法里面加上锁,然后再读取一次cache,如果无该对象,则添加对象,然后释放锁。毕竟读多写少,加锁性能损失不大。

xmuzyu
2009-05-13 20:55

>>其实只要在addModeltoCache的方法里面加上锁,然后再读取一次cache,如果无该对象,则添加对象,然后释放锁。毕竟读多写少,加锁性能损失不大。
恩,这样保证了放入缓存对象是唯一的,但是不能保证所有并发线程获得的对象都是唯一,并且会造成一些不必要的构造过程,构造过程也许很费时,不需要每个并发线程都构造一下。

3Go 1 2 3 下一页