zoukankan      html  css  js  c++  java
  • oddjob之smooth关闭程序

    java程序的smooth关闭策略可以采用hook跟观察者的模式实现

    无限等状态,如果状态出现可以关闭的事件则进行关闭

    虚拟机的关闭通过钩子调用关闭,如果关闭失败,在超时时间内强制杀掉jvm

    状态类

    public interface State {
    
        public boolean isStoppable();
        
    }
    package com.s.stat;
    
    
    
    /**
     * A Stateful job implements this interface so that 
     * it's state can be discovered. State is used to 
     * control the flow of execution within Oddjob, as
     * well as being a way of informing client applications
     * of progress.
     * 
     * @author Rob Gordon
     */
    public interface Stateful {
    
        /**
         * Add a job state listener.
         * 
         * @param listener The listener.
         * 
         */
        public void addStateListener(StateListener listener) ;
    
        /**
         * Remove a job state listener.
         * 
         * @param listener The listener.
         */    
        public void removeStateListener(StateListener listener);
    
        /**
         * Get the last state event.
         * 
         * @return The last State Event
         */
        public StateEvent lastStateEvent();
        
    }
    package com.s.stat;
    
    import java.io.Serializable;
    import java.util.Date;
    import java.util.EventObject;
    
    /**
     * An instance of this class is produced when a job state changes. It is
     * passed to all JobStateListeners.
     * 
     * @author Rob Gordon
     */
    
    public class StateEvent extends EventObject 
    implements Serializable {
    
        private static final long serialVersionUID = 20051026;
    
        static final String REPLACEMENT_EXCEPTION_TEXT = "Exception is not serializable, message is: ";
        
        private State state;
        private Date time;
        private Throwable exception;
        
        /**
         * Used to replace a non serializable exception.
         *
         */
        class ExceptionReplacement extends Exception {
            private static final long serialVersionUID = 20051217;
            public ExceptionReplacement(Throwable replacing) {
                super(REPLACEMENT_EXCEPTION_TEXT + replacing.getMessage());
                super.setStackTrace(exception.getStackTrace());
            }
        }
        
        /**
         * Constructor.
         * 
         * @param job The source of the event.
         * @param jobState The state.
         * @param time the Time of the event.
         * @param exception The exception if applicable, or null otherwise.
         */    
        public StateEvent(Stateful job, State jobState, Date time, Throwable exception) {
            super(job);
            if (jobState == null) {
                throw new NullPointerException("JobState can not be null!");
            }
            this.state = jobState;
            this.time = time;
            this.exception = exception;
        }
    
        /**
         * Constructor.
         * 
         * @param job The source of the event.
         * @param jobState The state.
         * @param exception The exception if applicable, or null otherwise.
         */
        public StateEvent(Stateful job, State jobState, Throwable exception) {
            this(job, jobState, new Date(), exception);
        }
    
        /**
         * Constructor.
         * 
         * @param job The source of the event.
         * @param jobState The state.
         */
        public StateEvent(Stateful job, State jobState) {
            this(job, jobState, null);
        }
    
        @Override
        public Stateful getSource() {
            return (Stateful) super.getSource();
        }
        
        /**
         * Get the job state.
         * 
         * @return The job state.
         */    
        public State getState() {
            return state;    
        }
    
        /**
         * Get the exception if applicable, null otherwise.
         * 
         * @return The exception of null.
         */    
        public Throwable getException() {
            return exception;
        }    
    
        /**
         * Get the time of the event..
         * 
         * @return The time.
         */
        public Date getTime() {
            return time;
        }
    
        /**
         * Override toString.
         */
        public String toString() {
            return "JobStateEvent, source=" + getSource() + ", " + state;
        }
        
        
    }
    package com.s.stat;
    
    
    
    /**
     * Implementors of this interface are able to listen to state events.
     * 
     * @author Rob Gordon
     */
    
    public interface StateListener {
    
    
        /**
         * Triggered when the job state changes.
         * 
         * @param event The job state event.
         */    
        public void jobStateChange(StateEvent event);
        
    }
    package com.s;
    
    import com.s.stat.StateEvent;
    import com.s.stat.StateListener;
    import com.s.stat.Stateful;
    
    
    public class Runner implements Runnable{
        public static final String KILLER_TIMEOUT_PROPERTY = "shutdown.killer.timeout";
    
        public static final long DEFAULT_KILLER_TIMEOUT = 15000L;
    
        /** Flag if program is being destroyed from the Shutdown Hook. */
        private volatile boolean destroying = false;
        
        /** The killer thread time out. */
        private final long killerTimeout;
    
        public Runner() {
            String timeoutProperty = System.getProperty(KILLER_TIMEOUT_PROPERTY);
            if (timeoutProperty == null) {
                killerTimeout = DEFAULT_KILLER_TIMEOUT;
            } else {
                killerTimeout = Long.parseLong(timeoutProperty);
            }
        }
    
        @Override
        public void run() {
            // TODO Auto-generated method stub
            Runtime.getRuntime().addShutdownHook(new ShutdownHook());        
            // Possibly wait for Oddjob to be in a stopped state.
            new StopWait(new Stateful() {
                
                @Override
                public void removeStateListener(StateListener listener) {
                    // TODO Auto-generated method stub
                    
                }
                
                @Override
                public StateEvent lastStateEvent() {
                    // TODO Auto-generated method stub
                    return null;
                }
                
                @Override
                public void addStateListener(StateListener listener) {
                    // TODO Auto-generated method stub
                    
                }
            }, Long.MAX_VALUE).run();
            
            // 调用程序的stop
            
            
        }
    
        /**
         * shutdown hook.
         * <p>
         * This Class has evolved quite a lot though trial and error due to
         * a lack of understanding of JVM shutdown. Should this thread be a
         * daemon? Current thinking is no because you don't want other daemon
         * threads to terminate until  has been shutdown properly.
         *
         */
        class ShutdownHook extends Thread {
            
            /** Killer thread will forcibly halt  if it hasn't terminated
             * cleanly. */
            private Thread killer;
            
            /*
             * (non-Javadoc)
             * @see java.lang.Thread#run()
             */
            public void run() {
    
            //    logger.info("Shutdown Hook Executing.");
                
                // killer will just kill process if we can't stop in 15 sec
                killer = new Thread(new Runnable() {
                    public void run() {
                        try {
                            Thread.sleep(killerTimeout);
                        }
                        catch (InterruptedException e) {
                        //    logger.debug("Killer thread interrupted and terminating.");
                            return;
                        }
    //                    logger.error("Failed to stop Oddjob nicely, using halt(-1)");
                        Runtime.getRuntime().halt(-1);
                    }
                });
                
                // start the killer. Not sure it really need to be daemon but
                // it does no harm.
    //            logger.debug("Starting killer thread.");
                killer.setDaemon(true);
                killer.start();
                
                // 调用程序的关闭
                
                
                // Nothing's hanging so we don't need our killer.
                //TODO 判断程序是否调用自身的关闭程序,如果成功则单端killer
    //            killer.interrupt();
                
            }
        }
    }
    package com.s;
    
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.TimeUnit;
    
    import com.s.stat.IsStoppable;
    import com.s.stat.State;
    import com.s.stat.StateEvent;
    import com.s.stat.StateListener;
    import com.s.stat.Stateful;
    
    /**
     * A utility class to provide wait until stopped functionality.
     * <p>
     * The default timeout is 5 seconds before a {@link FailedToStopException}
     * is thrown.
     * 
     * @author rob
     *
     */
    public class StopWait {
    
        private final Stateful stateful;
        
        private final long timeout;
        
        /**
         * Constructor with default timeout.
         * 
         * @param stateful The thing to wait until stopped.
         */
        public StopWait(Stateful stateful) {
            this(stateful, 5000);
        }
        
        /**
         * Constructor where timeout can be specified.
         * 
         * @param stateful The thing to wait until stopped.
         * @param timeout The timeout. Note that a timeout of 0 or less is
         * no timeout.
         */
        public StopWait(Stateful stateful, long timeout) {
            this.stateful = stateful;
            this.timeout = timeout;
        }
        
        /**
         * Run the stop wait. This will block until the job stops or the
         * timeout occurs.
         * 
         * @throws FailedToStopException If timeout occurs.
         */
        public void run()  {        
    
            if (new IsStoppable().test(
                    stateful.lastStateEvent().getState())) {
                doWait();
            }
        }
        
        private void doWait() {        
            
            final BlockingQueue<State> handoff = new LinkedBlockingQueue<State>();
            
            class StopListener implements StateListener {
                
                @Override
                public void jobStateChange(StateEvent event) {
                    handoff.add(event.getState());
                }
            };
            
            StopListener listener = new StopListener();
                    
            stateful.addStateListener(listener);
            
            try {
                while (true) {
    
                    State state = handoff.poll(timeout, TimeUnit.MILLISECONDS);
                    if (state == null) {
                    }
                    if (!state.isStoppable()) {
                        return;
                    }
                }
            }
            catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            finally {
                stateful.removeStateListener(listener);
            }
        }    
    }
  • 相关阅读:
    指定HTML标签属性 |Specifying HTML Attributes| 在视图中生成输出URL |高级路由特性 | 精通ASP-NET-MVC-5-弗瑞曼
    传递额外的值 Passing Extra Values |在视图中生成输出URL | 高级路由特性 | 精通ASP-NET-MVC-5-弗瑞曼
    以其他控制器为目标 在视图中生成输出URL
    数组与指针(数组中所有元素的和)
    OC中的指针
    UIScrollView创建相册
    开发之UI篇
    TabBarController
    适配ipone5
    NSDate 哪些事
  • 原文地址:https://www.cnblogs.com/blachie/p/3652484.html
Copyright © 2011-2022 走看看