RabbitMQ客户端源码分析(四)之BlockingCell

RabbitMQ-java-client版本

  1. com.rabbitmq:amqp-client:4.3.0
  2. RabbitMQ版本声明: 3.6.15

BlockingCell

  1. BlockingCell,代码文档注释描述为”简单的一次性IPC机制“,其实就是一个Future对象,大多数长连接里异步处理获取响应值都会采用Future模式。

  2. uml关联

BlockingCell源码分析

  1. 完整代码,我们从代码结构来看其实就是一个Future

    /**
     * Simple one-shot IPC mechanism. Essentially a one-place buffer that cannot be emptied once filled.
     * 简单的一次性IPC机制。 基本上是一个缓冲区,一旦填满就不能清空。
     * 从代码上来看其实就是一个Future对象
     */
    public class BlockingCell<T> {
        /** Indicator of not-yet-filledness
         *  尚未填充满的标示
         * */
        private boolean _filled = false;
    
        /** Will be null until a value is supplied, and possibly still then. */
        private T _value;
    
        private static final long NANOS_IN_MILLI = 1000 * 1000;
    
        private static final long INFINITY = -1;
    
        /** Instantiate a new BlockingCell waiting for a value of the specified type. */
        public BlockingCell() {
            // no special handling required in default constructor
        }
    
        /**
         * Wait for a value, and when one arrives, return it (without clearing it). If there's already a value present, there's no need to wait - the existing value
         * is returned.
         * 一直等待,直到拿到响应数据之后调用set(T newValue),设置值之后调用notifyAll(),此时get()不再阻塞。
         * @return the waited-for value
         *
         * @throws InterruptedException if this thread is interrupted
         */
        public synchronized T get() throws InterruptedException {
            while (!_filled) {
                wait();
            }
            return _value;
        }
    
        /**
         * Wait for a value, and when one arrives, return it (without clearing it). If there's
         * already a value present, there's no need to wait - the existing value is returned.
         * If timeout is reached and value hasn't arrived, TimeoutException is thrown.
         * 
         * @param timeout timeout in milliseconds. -1 effectively means infinity
         * @return the waited-for value
         * @throws InterruptedException if this thread is interrupted
         */
        public synchronized T get(long timeout) throws InterruptedException, TimeoutException {
            //如果设置为-1,则表示一直等待下去
            if (timeout == INFINITY) return get();
    
            if (timeout < 0) {
                throw new AssertionError("Timeout cannot be less than zero");
            }
    
            long now = System.nanoTime() / NANOS_IN_MILLI;
            long maxTime = now + timeout;
            while (!_filled && (now = (System.nanoTime() / NANOS_IN_MILLI)) < maxTime) {
                wait(maxTime - now);
            }
    
            if (!_filled)
                throw new TimeoutException();
    
            return _value;
        }
    
        /**
         * As get(), but catches and ignores InterruptedException, retrying until a value appears.
         * @return the waited-for value
         */
        public synchronized T uninterruptibleGet() {
            boolean wasInterrupted = false;
            try {
                while (true) {
                    try {
                        return get();
                    } catch (InterruptedException ex) {
                        // no special handling necessary
                        wasInterrupted = true;
                    }
                }
            } finally {
                if (wasInterrupted) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    
        /**
         * As get(long timeout), but catches and ignores InterruptedException, retrying until
         * a value appears or until specified timeout is reached. If timeout is reached,
         * TimeoutException is thrown.
         * We also use System.nanoTime() to behave correctly when system clock jumps around.
         * 
         * @param timeout timeout in milliseconds. -1 means 'infinity': never time out
         * @return the waited-for value
         */
        public synchronized T uninterruptibleGet(int timeout) throws TimeoutException {
            long now = System.nanoTime() / NANOS_IN_MILLI;
            long runTime = now + timeout;
            boolean wasInterrupted = false;
            try {
                do {
                    try {
                        return get(runTime - now);
                    } catch (InterruptedException e) {
                        // Ignore.
                        wasInterrupted = true;
                    }
                } while ((timeout == INFINITY) || ((now = System.nanoTime() / NANOS_IN_MILLI) < runTime));
            } finally {
                if (wasInterrupted) {
                    Thread.currentThread().interrupt();
                }
            }
    
            throw new TimeoutException();
        }
    
        /**
         * Store a value in this BlockingCell, throwing AssertionError if the cell already has a value.
         *
         * @param newValue the new value to store
         */
        public synchronized void set(T newValue) {
            if (_filled) {
                throw new AssertionError("BlockingCell can only be set once");
            }
            _value = newValue;
            _filled = true;
            notifyAll();
        }
    
        /**
         * Store a value in this BlockingCell if it doesn't already have a value.
         * @return true if this call to setIfUnset actually updated the BlockingCell; false if the cell already had a value.
         * @param newValue the new value to store
         */
        public synchronized boolean setIfUnset(T newValue) {
            if (_filled) {
                return false;
            }
            set(newValue);
            return true;
        }
    }
    
    

ValueOrException

  1. ValueOrException值与异常的包装。

    public class ValueOrException<V, E extends Throwable & SensibleClone<E>> {
        private final boolean _useValue;
        private final V _value;
        private final E _exception;
        ......
    }
    
    

BlockingValueOrException

  1. BlockingValueOrExceptionBlockingCell的扩展类,泛型参数是ValueOrException

    public class BlockingValueOrException<V, E extends Throwable & SensibleClone<E>>
        extends BlockingCell<ValueOrException<V, E>>
    {
        public void setValue(V v) {
            super.set(ValueOrException.<V, E>makeValue(v));
        }
    
        public void setException(E e) {
            super.set(ValueOrException.<V, E>makeException(e));
        }
    
        public V uninterruptibleGetValue() throws E {
            return uninterruptibleGet().getValue();
        }
    
        public V uninterruptibleGetValue(int timeout) throws E, TimeoutException {
        	return uninterruptibleGet(timeout).getValue();
        }
    }
    

RpcContinuation

  1. rpc配置接口

     public interface RpcContinuation {
        void handleCommand(AMQCommand command);
        void handleShutdownSignal(ShutdownSignalException signal);
    }
    
    public static abstract class BlockingRpcContinuation<T> implements RpcContinuation {
        public final BlockingValueOrException<T, ShutdownSignalException> _blocker =
            new BlockingValueOrException<T, ShutdownSignalException>();
    
        //将响应的结果存入到Future对象中(BlockingCell)
        @Override
        public void handleCommand(AMQCommand command) {
            _blocker.setValue(transformReply(command));
        }
    
        @Override
        public void handleShutdownSignal(ShutdownSignalException signal) {
            _blocker.setException(signal);
        }
    
        public T getReply() throws ShutdownSignalException
        {
            return _blocker.uninterruptibleGetValue();
        }
    
        public T getReply(int timeout)
            throws ShutdownSignalException, TimeoutException
        {
            return _blocker.uninterruptibleGetValue(timeout);
        }
        //获取响应的结果
        public abstract T transformReply(AMQCommand command);
    }
    
    public static class SimpleBlockingRpcContinuation
        extends BlockingRpcContinuation<AMQCommand>
    {
        @Override
        public AMQCommand transformReply(AMQCommand command) {
            return command;
        }
    }
    

扩展

自己写一个

  1. 这里是我之前学习netty时候写的一个Future对象以及实现,供参考

  2. ResponseFuture接口

    public interface ResponseFuture<T> {
    
        T get()  throws InterruptedException;
    
        T get(final long timeoutMillis)  throws InterruptedException;
        
        boolean isCancelled();
    
        boolean isDone();
    
        boolean isSuccess();
    
        void setResult(T result);
    
        void setFailure(Throwable err);
    
        boolean isTimeout();
        
        public long getCreateTime();
    
        public long getTimeoutInMillis();
        
        public void executeAsyncInvokeCallback();
        
        public void setAsyncInvokeCallback(AsyncInvokeCallback<T> invokeCallback);
        
        public boolean hasCallback();
    }
    
  3. AbstractResponseFuture抽象类

    package cn.jananl.netty.transport;
    
    import java.util.concurrent.CountDownLatch;
    public abstract class AbstractResponseFuture<T> implements ResponseFuture<T>{
    
        public enum FutureState {
            /**新建任务 **/
            NEW(0),
            /** 任务完成 **/
            DONE(1),
            /** 任务取消**/
            CANCELLED(2),
            /**
             * 任务超时
             */
            TIMEOUT(3);
            private int state;
            FutureState(int state) {
                this.state = state;
            }
        }
        protected final CountDownLatch countDownLatch = new CountDownLatch(1);
        
        
        protected volatile FutureState state = FutureState.NEW; //状态
        
        protected final long createTime = System.currentTimeMillis();//处理开始时间
    
        /**
         * 本地调用的超时时间
         */
        protected long timeoutInMillis;
    
        public AbstractResponseFuture(long timeoutInMillis) {
            this.timeoutInMillis = timeoutInMillis;
        }
    
        @Override
        public boolean isCancelled() {
            return this.state == FutureState.CANCELLED;
        }
    
        @Override
        public boolean isDone() {
            return this.state == FutureState.DONE;
        }
    
        @Override
        public boolean isTimeout() {
            return createTime + timeoutInMillis < System.currentTimeMillis();
        }
    
        public long getCreateTime() {
            return createTime;
        }
    
        public long getTimeoutInMillis() {
            return timeoutInMillis;
        }
    }
    
  4. DefaultResponseFuture具体实现

    package cn.jananl.netty.transport;
    
    import java.util.concurrent.TimeUnit;
    /**
     * 默认响应future
     * @author jannal
     * @param <T>
     */
    public class DefaultResponseFuture<T> extends AbstractResponseFuture<T>{
    
        private volatile T result;
        private volatile Throwable throwable;
        private  AsyncInvokeCallback<T> invokeCallback;
        
        public DefaultResponseFuture(long timeoutInMillis) {
            super(timeoutInMillis);
        }
    
        @Override
        public T get() throws InterruptedException {
            if(!this.isDone()) {
                this.countDownLatch.await(super.timeoutInMillis, TimeUnit.MILLISECONDS);
            }
            if(this.throwable!=null){
                if(this.state==FutureState.CANCELLED){
                    throw new RuntimeException("任务被取消");
                }else{
                    throw new RuntimeException(this.throwable);
                }
            }else{
                return this.result;
            }
           
        }
    
        @Override
        public T get(long timeout) throws InterruptedException {
            if(!this.isDone()) {
                this.countDownLatch.await(timeout, TimeUnit.MILLISECONDS);
            }
            return result; 
        }
    
        @Override
        public boolean isSuccess() {
            return isDone()&&throwable==null;
        }
    
    
        @Override
        public void setFailure(Throwable cause) {
            if(!this.isDone()) {
                this.setFailure(cause);
                this.state = FutureState.DONE;
                this.countDownLatch.countDown();
            }
        }
    
        @Override
        public void setResult(T result) {
            if(!this.isDone()){
                this.result = result;
                this.state = FutureState.DONE;
                this.countDownLatch.countDown();
            }
            
        }
    
        @Override
        public void executeAsyncInvokeCallback() {
            if(invokeCallback!=null){
                invokeCallback.operationComplete(this);
            }
            
        }
    
        @Override
        public void setAsyncInvokeCallback(AsyncInvokeCallback<T> invokeCallback) {
           this.invokeCallback =  invokeCallback;
            
        }
    
        @Override
        public boolean hasCallback() {
            if(invokeCallback!=null){
                return true;
            }
            return false;
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值