是EJB辛格尔顿同步?

问题描述 投票:0回答:3

我已经实现了一种缓存豆缓存数据对象为EJB辛格尔顿。我不知道这是在EJB的正确方法:

@Singleton
public class MyCache {

    int DEFAULT_CACHE_SIZE = 30;
    int DEFAULT_EXPIRES_TIME = 60000;
    long expiresTime = 0;
    long lastReset = 0;
    Cache cache = null; 

    ....
    @PostConstruct
    void init() {
        resetCache();
    }

    public void resetCache() {
        cache = new Cache(DEFAULT_CACHE_SIZE);
        lastReset = System.currentTimeMillis();
    }

    public void put(String key, Object value) {
        cache.put(key, value);
    }

    public Object get(String key) {
        // test if cache is expired
        if (expiresTime > 0) {
            Long now = System.currentTimeMillis();
            if ((now - lastReset) > expiresTime) {
                logger.finest("...... Cache expired!");
                resetCache();
            }
        }
        return cache.get(key);
    }



    class Cache extends LinkedHashMap<String, Object> implements Serializable {
        private static final long serialVersionUID = 1L;
        private final int capacity;

        public Cache(int capacity) {
            super(capacity + 1, 1.1f, true);
            this.capacity = capacity;
        }

        protected boolean removeEldestEntry(Entry<String, Object> eldest) {
            return size() > capacity;
        }
    }
}

我的问题是:这是执行程序范围的缓存机制的正确方法?

我有一个缓存的内容被意外地改变了印象。会发生这种事?例如,如果EJB被钝化?我在Payara41服务器上运行。

或者我必须使用:

cache = Collections.synchronizedMap(new Cache(DEFAULT_CACHE_SIZE));

代替:

cache = new Cache(DEFAULT_CACHE_SIZE);
singleton ejb linkedhashmap
3个回答
1
投票

首先,不为bean指定的并发性管理,它下降到默认的“容器”。

从EJB 3.1规范:

当设计一个Singleton会话bean,开发者必须确定Bean将使用容器是否管理或豆管理的并发。通常,辛格尔顿豆将被指定为具有容器管理的并发划分。这是如果没有指定并发管理类型的默认。

然后,容器并发管理需要锁定型的方法级规格。只要那些是没有的,默认的“写”适用于:

默认情况下,如果不是一个Singleton豆与容器管理的并发划界的方法中指定的并发性锁定属性注释,该方法的并发锁定属性的值被定义为写入。

访问您的bean的方法的上述手段必须是同步的,甚至可能超过你的实际需要。您可以设置“读取”锁定类型只读方法(GET),以允许并发读取访问。


0
投票

和容器管理锁的解决方案有一个缺点,考虑是否有写锁放置操作就意味着整个“高速缓存”被阻断,因此获取或发布是可以并行,无论关键是不同的。如果你的缓存实现是一个并行地图​​,你可以使用它没有锁定。

如果您有缓存更多的要求,我会用的Infinispan它们提供了更好的性能。这里的高速缓存可以是本地或分布在集群。


0
投票

阅读本blog from Adam Bien后,我现在提高了我下面的方式代码:

  • 我加了注释ConcurrencyManagement
  • 我改变了我的LinkedHashMap到的ConcurrentHashMap。

例:

@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN) // added concurrency management
public class MyCache {

    int DEFAULT_CACHE_SIZE = 30;
    int DEFAULT_EXPIRES_TIME = 60000;
    long expiresTime = 0;
    long lastReset = 0;
    Cache cache = null; 

    ....
    @PostConstruct
    void init() {
        resetCache();
    }

    public void resetCache() {
        cache = new Cache(DEFAULT_CACHE_SIZE);
        lastReset = System.currentTimeMillis();
    }

    public void put(String key, Object value) {
        cache.put(key, value);
    }

    public Object get(String key) {
        // test if cache is expired
        if (expiresTime > 0) {
            Long now = System.currentTimeMillis();
            if ((now - lastReset) > expiresTime) {
                logger.finest("...... Cache expired!");
                resetCache();
            }
        }
        return cache.get(key);
    }

    // changed from LinkedHashMap to ConcurrentHashMap
    class Cache extends ConcurrentHashMap<String, Object> implements Serializable {
        private static final long serialVersionUID = 1L;
        private final int capacity;

        public Cache(int capacity) {
            super(capacity + 1, 1.1f);
            this.capacity = capacity;
        }

        protected boolean removeEldestEntry(Entry<String, Object> eldest) {
            return size() > capacity;
        }
    }
}

我觉得这是现在更正确实施。

© www.soinside.com 2019 - 2024. All rights reserved.