基于memcache的java分布式队列实现。

主要有两个类,一个队列类和一个job的抽象类。

保证队列类中的key的唯一性,就可以用spring配置多个实例。水平有限,欢迎吐槽。

上代码:

1、队列类

import net.spy.memcached.MemcachedClient;
import net.spy.memcached.internal.OperationFuture;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.izx.services.common.Constant;

/**
 * 
* @ClassName: MemCacheQueue 
* @Description: 基于memcache的消息队列的实现
* @author hai.zhu
* @date 2016-3-31 下午3:29:00 
*
 */
public class MemCacheQueue implements InitializingBean, DisposableBean,ApplicationContextAware {
    private static final Log log = LogFactory.getLog(MemCacheQueue.class);
    
    /**
     * 队列名
     */
    private String key;
    
    /**
     * 队列锁失效分钟
     */
    private Integer lockExpireMinite = 3;
    
    private MemcachedClient memcachedClient;
    
    private ApplicationContext applicationContext;
    
    ListenerThread listenerThread = new ListenerThread();
    
    public void setKey(String key) {
        this.key = key;
    }
    
    public void setMemcachedClient(MemcachedClient memcachedClient) {
        this.memcachedClient = memcachedClient;
    }
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void destroy() throws Exception {
        try {
            this.sign = false;
            listenerThread.interrupt();
        } catch (Exception e) {
            log.error(e);
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        //初始化队列,用add防止重启覆盖
        memcachedClient.add(Constant.MEMCACHE_GLOBAL_QUEUE_STARTKEY + key, 0, "0");
        memcachedClient.add(Constant.MEMCACHE_GLOBAL_QUEUE_ENDKEY + key, 0, "0");
        //设置任务线程
        listenerThread.setDaemon(true);
        listenerThread.start();
    }
    
    /**
     * 
    * @Title: push 
    * @Description: 唯一对外方法,放入要执行的任务
    * @param @param value
    * @param @throws Exception    设定文件 
    * @return void    返回类型 
    * @throws
     */
    public synchronized void push(MemCacheQueueJobAdaptor value) throws Exception {
        //分布加锁
        queuelock();
        //放入队列
        memcachedClient.incr(Constant.MEMCACHE_GLOBAL_QUEUE_ENDKEY + key, 1);
        Object keyorder = memcachedClient.get(Constant.MEMCACHE_GLOBAL_QUEUE_ENDKEY + key);
        memcachedClient.set(Constant.MEMCACHE_GLOBAL_QUEUE_VARIABLE + key + "_" + keyorder, 0, value);
        //分布解锁
        queueUnLock();
    }
    
    /**
     * 
    * @Title: pop 
    * @Description: 取出要执行的任务
    * @param @return
    * @param @throws Exception    设定文件 
    * @return MemCacheQueueJobAdaptor    返回类型 
    * @throws
     */
    private synchronized MemCacheQueueJobAdaptor pop() throws Exception {
        Object keyorderstart = memcachedClient.get(Constant.MEMCACHE_GLOBAL_QUEUE_STARTKEY + key);
        Object keyorderend = memcachedClient.get(Constant.MEMCACHE_GLOBAL_QUEUE_ENDKEY + key);
        if(keyorderstart.equals(keyorderend)){
            return null;
        }
        MemCacheQueueJobAdaptor adaptor = (MemCacheQueueJobAdaptor)memcachedClient.get(Constant.MEMCACHE_GLOBAL_QUEUE_VARIABLE + key + "_" + keyorderstart);
        memcachedClient.incr(Constant.MEMCACHE_GLOBAL_QUEUE_STARTKEY + key, 1);
        memcachedClient.delete(Constant.MEMCACHE_GLOBAL_QUEUE_VARIABLE + key + "_" + keyorderstart);
        return adaptor;
    }
    
    /**
     * 
    * @Title: queuelock 
    * @Description: 加锁
    * @param @throws InterruptedException    设定文件 
    * @return void    返回类型 
    * @throws
     */
    private void queuelock() throws Exception {
        do {
            OperationFuture<Boolean> sign = memcachedClient.add(Constant.MEMCACHE_GLOBAL_QUEUE_LOCK + key, lockExpireMinite * 60, key);
            if(sign.get()){
                return;
            } else {
                log.debug("key: " + key + " locked by another business");
            }
            Thread.sleep(300);
        } while (true);
    }
    
    /**
     * 
    * @Title: queueUnLock 
    * @Description: 解锁
    * @param     设定文件 
    * @return void    返回类型 
    * @throws
     */
    private void queueUnLock() {
        memcachedClient.delete(Constant.MEMCACHE_GLOBAL_QUEUE_LOCK + key);
    }
    
    private boolean sign = true;
    private long THREAD_SLEEP = 10;
    class ListenerThread extends Thread {
        @Override
        public void run(){
            log.error("队列["+key+"]开始执行");
            while(sign){
                try {
                    Thread.sleep(THREAD_SLEEP);
                    dojob();
                } catch (Exception e) {
                    log.error(e);
                }
            }
        }
        
        private void dojob(){
            try{
                queuelock();
                MemCacheQueueJobAdaptor adaptor = pop();
                //逐个执行
                if(adaptor != null){
                    THREAD_SLEEP = 10;
                    try {
                        adaptor.setApplicationContext(applicationContext);
                        adaptor.onMessage();
                    } catch (Exception e) {
                        log.error(e);
                    }
                }else{
                    THREAD_SLEEP = 5000;
                }
            }catch(Exception e){
                log.error(e);
            }finally{
                queueUnLock();
            }
        }
    }
}

2、job抽象类

import org.springframework.context.ApplicationContext;
import java.io.Serializable;

/**
 * 
 * @ClassName: MemCacheQueueJobAdaptor 
 * @Description: 基于memcache队列的任务适配器
 * @author hai.zhu
 * @date 2015-12-11 上午11:48:26 
 * @param <T>
 */
public abstract class MemCacheQueueJobAdaptor implements Serializable{
    private static final long serialVersionUID = -5071415952097756327L;
    
    private ApplicationContext applicationContext;
    
    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
    
    /**
     * 
     * @Title: onMessage 
     * @Description: 异步执行任务接口
     * @author hai.zhu
     * @param @param value 设定文件 
     * @return void 返回类型 
     * @throws
     */
    public abstract void onMessage();
}

3、部分放在constant的常量

/**
     * 基于memcache的队列存放前缀
     */
    public static String MEMCACHE_GLOBAL_QUEUE_VARIABLE = "MEMCACHE_GLOBAL_QUEUE_VARIABLE_";
    
    /**
     * 基于memcache的队列锁的前缀
     */
    public static String MEMCACHE_GLOBAL_QUEUE_LOCK = "MEMCACHE_GLOBAL_QUEUE_LOCK_";
    
    /**
     * 基于memcache的队列锁的开始元素
     */
    public static String MEMCACHE_GLOBAL_QUEUE_STARTKEY = "MEMCACHE_GLOBAL_QUEUE_STARTKEY_";
    
    /**
     * 基于memcache的队列锁的结束元素
     */
    public static String MEMCACHE_GLOBAL_QUEUE_ENDKEY = "MEMCACHE_GLOBAL_QUEUE_ENDKEY_";

4、spring配置,保证队列名的唯一性就可以配置多个队列

<!-- 枚举类型需要转换 -->
    <bean id="KETAMA_HASH" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">    
        <property name="staticField" value="net.spy.memcached.DefaultHashAlgorithm.KETAMA_HASH" />    
    </bean>
    
    <!-- memcache客户端 -->
    <bean id="memcachedClient" class="net.spy.memcached.spring.MemcachedClientFactoryBean">
        <property name="servers" value="192.168.75.154:11277,192.168.75.154:11277,192.168.75.154:11277"/>
        <property name="protocol" value="BINARY"/>
        <property name="transcoder">
            <bean class="net.spy.memcached.transcoders.SerializingTranscoder">
                <property name="compressionThreshold" value="1024"/>
            </bean>
        </property>
        <property name="opTimeout" value="1000"/>
        <property name="timeoutExceptionThreshold" value="1998"/>
        <property name="hashAlg" ref="KETAMA_HASH"/>
        <property name="locatorType" value="CONSISTENT"/> 
        <property name="failureMode" value="Redistribute"/>
        <property name="useNagleAlgorithm" value="false"/>
    </bean>
    
    <!-- 队列配置 -->
    <bean id="onequeue" class="com.izx.services.queque.MemCacheQueue">
        <property name="memcachedClient" ref="memcachedClient"/>
        <property name="key" value="onequeue"/>
    </bean>


转载于:https://my.oschina.net/zhuxuan/blog/650935

  1.Memcached是什么?   Memcached是高性能的,分布式的内存对象缓存系统,用于在动态应用中减少数据库负载,提升访问速度。Memcached通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。Memcached由Danga Interactive最初为了加速 LiveJournal网站访问速度而开发的,后 来被很多大型的网站采用。起初作者编写它可能是为了提高动态网页应用,为了减轻数据库检索的压力,来做的这个缓存系统。它的缓存是一种分布式的,也就是可 以允许不同主机上的多个用户同时访问这个缓存系统,这种方法不仅解决了共享内存只能是单机的弊端, 同时也解决了数据库检索的压力,最大的优点是提高了访问获取数据的速度!基于memcached作者对分布式cache的理解和解决方案。memcached完全可以用到其他地方 比如分布式数据库,分布式计算等领域。Memcached将数据库负载大幅度降低,更好的分配资源,更快速访问。   2.Memcached工作机制   通过在内存中开辟一块区域来维持一个大的hash表来加快页面访问速度,和数据库是独立的。但是目前主要用来缓存数据库的数据。允许多个server通过网络形成一个大的hash,用户不必关心数据存放在哪,只调用相关接口就可。存放在内存的数据通过LRU算法进行淘汰出内存。同时可以通过删除和设置失效时间来淘汰存放在内存的数据。   现在一些.NET开发人员开始放弃ASP.NET内置的缓存机制,转而使用Memcached——一种分布式的内存缓存系统。当运行在单独的Web服务器上,你可以很容易地清除一个已经确认被改变了的缓存。可惜,ASP.NET没有一个很好的方法来支持多服务器。每个服务器上的缓存都对其他缓存的改变一无所知。   ASP.NET允许通过基于文件系统和数据库表的触发器来作废一个缓存。然而,这也存在问题,比如数据库触发器需要使用昂贵的轮询,以及触发器本身冗长的编程。但是,我们还是有其他的选择的。   不像ASP.NET内置的缓存机制,Memcached是一个分布式的缓存系统。任何Web服务器都能更新或删除一个缓存项,并且所有其他的服务器都能在下次访问这些缓存项的时候自动获取到更新的内容。这是通过把这些缓存项存储在一个或者多个缓存服务器上来实现的。每一个缓存项都根据它的关键字的哈希值来分配到一个服务器上。 注:相关组词来源于百度文库
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值