flowable源码解读——内存缓存设计

最近检查flowable缓存问题,顺便看了下源码,flowable默认是将缓存存储在内存中,以减少对数据库的压力,以下是flowable缓存类的设计。

DeploymentCache接口设计:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.flowable.common.engine.impl.persistence.deploy;

public interface DeploymentCache<T> {
    T get(String var1);

    boolean contains(String var1);

    void add(String var1, T var2);

    void remove(String var1);

    void clear();
}

 DefaultDeploymentCache<T>类设计:

/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.flowable.common.engine.impl.persistence.deploy;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Default cache: keep everything in memory, unless a limit is set.
 * 
 * @author Joram Barrez
 */
public class DefaultDeploymentCache<T> implements DeploymentCache<T> {

    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultDeploymentCache.class);

    protected Map<String, T> cache;

    /** Cache with no limit */
    public DefaultDeploymentCache() {
        this.cache = Collections.synchronizedMap(new HashMap<>());
    }

    /**
     * Cache which has a hard limit: no more elements will be cached than the limit.
     */
    public DefaultDeploymentCache(final int limit) {
        this.cache = Collections.synchronizedMap(new LinkedHashMap<String, T>(limit + 1, 0.75f, true) { // +1 is needed, because the entry is inserted first, before it is removed
            // 0.75 is the default (see javadocs)
            // true will keep the 'access-order', which is needed to have a real LRU cache
            private static final long serialVersionUID = 1L;

            @Override
            protected boolean removeEldestEntry(Map.Entry<String, T> eldest) {
                boolean removeEldest = size() > limit;
                if (removeEldest && LOGGER.isTraceEnabled()) {
                    LOGGER.trace("Cache limit is reached, {} will be evicted", eldest.getKey());
                }
                return removeEldest;
            }

        });
    }

    @Override
    public T get(String id) {
        return cache.get(id);
    }

    @Override
    public void add(String id, T obj) {
        cache.put(id, obj);
    }

    @Override
    public void remove(String id) {
        cache.remove(id);
    }

    @Override
    public boolean contains(String id) {
        return cache.containsKey(id);
    }

    @Override
    public void clear() {
        cache.clear();
    }

    // For testing purposes only
    public Collection<T> getAll() {
        return cache.values();
    }

    // For testing purposes only
    public int size() {
        return cache.size();
    }

}

 通过源码可以看到 flowable 是用 Collections.synchronizedMap 的方式保证缓存写入的线程安全问题。创建线程安全的Map主要有以下三种方式:

// 无非就是以下三种方式
Map<String, Object> map2 = new Hashtable<String, Object>();

Map<String, Object> map3 = new ConcurrentHashMap<String, Object>();

Map<String, Object> map4 = Collections.synchronizedMap(new HashMap<String, Object>());

Collections.synchronizedMap 是使用一个包装器类来实现的。ConcurrentHashMap 是使用数组+链表来实现的。

1・Collections.synchronizedMap() : 这是一个静态工厂方法,它接收一个现有的 Map 实例作为参数,并返回一个经过包装的线程安全的 Map。使用一个全局的锁来确保线程安全,无论是读取还是写入操作都会获取这把锁,这意味着所有的操作都是互斥的,即在同一时刻只能有一个线程进行操作,因此不能说它是原子级别的操作,除非操作本身就是原子性的(例如,简单的 get 或 put 操作针对的是单个对象引用)。在高并发环境下,当多个线程同时访问不同的键值对时,可能会导致性能瓶颈。

2・ConcurrentHashMap :采用了一种粒度更细的锁机制(通常称为分段锁或者分区锁),将内部的数据结构划分为多个部分或桶(bucket),每个桶都可以独立地加锁和解锁,从而实现了更高的并发性能。在大多数情况下,多个线程可以同时对不同键进行读写操作,而不会相互阻塞,除非它们碰巧要修改同一个桶内的数据。

 通过以上对比可以看到 Collections.synchronizedMap()的方式并不是原子级别的锁定,在高并发下有性能瓶颈,不太理解为什么flowable不用ConcurrentHashMap 这种方式做内存缓存,也许是考虑对流程定义的读写不会太频繁才这么设计。

如果对并发很高的场景 可以用ConcurrentHashMap 这种方式实现,以下是实现代码:

package org.flowable.common.engine.impl.persistence.deploy;

import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DefaultDeploymentCacheConcurrent<T> implements DeploymentCache<T> {
    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultDeploymentCacheConcurrent.class);
    protected ConcurrentHashMap<String, T> cache;

    public DefaultDeploymentCacheConcurrent() {
        this.cache = new ConcurrentHashMap<>();
    }

    public DefaultDeploymentCacheConcurrent(final int limit) {
        this.cache = new ConcurrentHashMap<>(limit + 1, 0.75f, 1); // concurrencyLevel set to 1 for simplicity
    }

    public T get(String id) {
        return this.cache.get(id);
    }

    public void add(String id, T obj) {
        this.cache.put(id, obj);
    }

    public void remove(String id) {
        this.cache.remove(id);
    }

    public boolean contains(String id) {
        return this.cache.containsKey(id);
    }

    public void clear() {
        this.cache.clear();
    }

    public Collection<T> getAll() {
        return this.cache.values();
    }

    public int size() {
        return this.cache.size();
    }
}

以上是基于内存的缓存设计,这边现在有项目是部署在负载环境下,内存缓存已经不能满足需求,后续会将内存存储到redis库。

flowable源码解读是指对flowable工作流引擎的源代码进行分析和理解。flowable是一个开源的工作流引擎,用于实现和管理复杂的业务流程。在源码解读过程中,可以深入了解flowable设计原理、核心组件和算法实现。 根据引用,流程定义是将一个流程XML文件部署到flowable中,从而创建一个定义好的流程。因此,在flowable源码解读中,可以关注流程定义的实现方式和流程XML文件的解析过程。 引用中提到了从基础讲起,结合应用场景,由浅入深地解释BPMN和Flowable的相关组件,并结合具体实例演示功能的使用和注意事项。这表明在源码解读中,可以结合实际应用场景,逐步深入地了解Flowable的不同组件的实现原理和使用方式。 引用中介绍了BPMN2.0定义的流程元素,包括流程对象、连接对象、泳道和数据和制品。在源码解读中,可以重点关注这些元素的实现和它们在flowable源代码中的具体实现方式。 总而言之,flowable源码解读是通过对flowable工作流引擎的源代码进行分析和理解,来深入了解flowable设计原理、核心组件和算法实现。通过结合实际应用场景和流程定义的解析过程,我们能够更加全面地理解flowable工作流引擎的实现原理和使用方式。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Flowable从入门到源码分析](https://blog.csdn.net/weixin_46399870/article/details/130277499)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [Flowable从入门到精通源码](https://download.csdn.net/download/qq_36305027/85422953)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值