用 Proxy 简化加锁代码,用 ReadWriteLock 以提高并行性

本文介绍了一种使用Java反射代理简化加锁代码的方法,并通过ReadWriteLock提高服务的并行性。具体展示了如何为一个核心服务接口实现状态检查和加锁,确保线程安全的同时提升效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java.lang.reflect.Proxy 简化加锁代码,用 ReadWriteLock 以提高并行性
 
有一个 CoreManager 接口,用来代表一个服务,每个方法对应服务的一个子功能。
 
方法 startup() 要求服务在 stoped 状态。
方法 shutdown() 要求服务在 started 状态。
方法 isStarted() 要求服务在 stoped/started 状态。
其它方法,要求服务在 started 状态。
 
 

/**
 *Allmehtodwillthrow{@link ManageException}thenTargetserverstoped.
 *
 */
publicinterface CoreManager {
 
      // ------- Target Server Control ---------------------------
      /**
       *ShutdownTargetServerCore.
       * 
       *@throwsManageExceptionstartuperror
       */
      publicvoid startup() throws ManageException;
 
      /**
       *ShutdownTargetServerCore.
       * 
       *@throwsManageExceptionshutdownerror
       */
      publicvoid shutdown() throws ManageException;
     
      /**
       *returntureifTargetServerisstarted
       *@returntheresult
       *  
       */
      publicboolean isStarted();
     
      /**
       *Reconfigurethelogsetting
       *
       *@paramlogConfig
       *@throwsManageException
       */
      publicvoid configureLog(LogConfig logConfig) throws ManageException;
 
      // ------- Component Manage-------------------------------
      /**
       *Addcomponent.
       *
       *@paramcomponentInfo
       *@throwsManageExceptionaddfail.
       */
      publicvoid addComponent(AbstractComponentBean componentInfo)
                  throws ManageException;
 
      /**
       *Returnallcomponentnames.
       *
       *@returnnotnull
       *@throwsManageException
       */
      public String[] getAllComponentNames() throws ManageException;
 
      /**
       *Returnthecomponentsetting.
       *
       *@paramcomponentName
       *@returnresultnotnull
       *@throwsManageExceptioncomponentnotfound
       */
      public AbstractComponentBean getComponentInfo(String componentName)
                  throws ManageException;
 
      /**
       *Removecomponent.
       *
       *@paramcomponentName
       *@throwsManageExceptioncomponentnotfound
       */
      publicvoid removeComponent(String componentName) throws ManageException;
 
      /**
       *Applynewroutinggraph
       *
       *@deprecateduse{@link #setNewRouting(ComponentConnector[])}instead
       *@paramroutingBeans
       *@returntureonlyifallconnectorisseted
       *@throwsManageException
       */
      @Deprecated
      publicboolean setNewRouting(ConnectorBean[] routingBeans) throws ManageException;
 
      /**
       *Applynewroutinggraph
       *
       *@paramroutingBeans
       *@returntureonlyifallconnectorisseted
       *@throwsManageException
       */
      publicboolean setNewRouting(ComponentConnector[] routingBeans) throws ManageException;
 
      /**
       *Changecomponentsetting
       *
       *@paramcomponentBean
       *@throwsManageExceptioncomponentnotfound
       */
      publicvoid changeComponentSetting(AbstractComponentBean componentBean)
                  throws ManageException;
 
      /**
       *Returntrueifcomponentexsit.
       *
       *@paramcomponentName
       *@returntheresult
       *@throwsManageException
       */
      publicboolean isComponentExist(String componentName) throws ManageException;
 
      /**
       *Getthedevicecomponentstatus.
       *Ifthecomponentin<code>componentNames</code>notexist,UNKNOWNwillreturn.
       *
       *@paramcomponentNames
       *@returnresult
       *@throwsManageException
       */
      public ConnectionStatus[] getDeviceComponentStatus(String[] componentNames) throws ManageException;
 
      /**
       *Settheenabledpropertyofcomponent.
       *
       *@paramcomponentName
       *@paramenabled
       *@throwsManageExceptioncomponentnotfound.
       */
      publicvoid setComponentEnabledProperty(String componentName,
                  boolean enabled) throws ManageException;
 
      // ------- Reader Control ----------------------------------
      publicvoid setAutoModeOn(String deviceName) throws ManageException;
 
      publicvoid setAutoModeOff(String deviceName) throws ManageException;
 
      public String getVersionNumber(String readerName) throws ManageException;
 
      publiclong getNumberOfReads(String readerName) throws ManageException;
 
      publiclong[] getNumberOfReads(String[] readerNames) throws ManageException;
 
      public Collection<DRFITag> readTags(String readerName)
                  throws ManageException;
 
      public Collection<DRFITag> readTags(String readerName, int antennaSequenceNo)
                  throws ManageException;
 
      public Collection<DRFITag> readTags(String readerName,
                  int[] antennaSequenceNo) throws ManageException;
 
      publicvoid writeTag(String deviceName, String writeFlag, String epc,
                  String userData, String killCode, int antennaSequenceNo)
                  throws ManageException;
 
      publicvoid killTag(String deviceName, String uri, String killCode,
                  int antennaSequence) throws ManageException;
 
      publicvoid setReadPower(String deviceName, int powerPercent)
                  throws ManageException;
 
      /**
       *Sendacommand(Event)toacomponent
       *
       *@paramtargetCompName
       *@paramevent
       *@returnmaynull
       *@throwsManageExceptionComponentnotfound/stoped.
       */
      public Object sendEvent2Component(String targetCompName, Object event)
                  throws ManageException;
 
      /**
       *Sendacommand(Event)toacomponent
       *
       *@paramtargetCompName
       *@paramsrcCompInfo
       *@paramevent
       *@returnmaynull
       *@throwsManageExceptionComponentnotfound/stoped.
       */
      public Object sendComponentEvent2Component(String targetCompName,
                  ConnectorEndpoint srcCompInfo, Object event)
                  throws ManageException;
     
     
      public List<ComponentConnector> getAllConnectors() throws ManageException;
 
      publicvoid addConnector(ComponentConnector connector) throws ManageException;
 
      publicvoid removeConnector(ComponentConnector connector) throws ManageException;
 
}
 
 
有这样一个最核心的实现:
 

publicclass ManagerImpl implements CoreManager {
 
      privatefinal TargetServerCore TargetServer;
 
      privatestaticfinal Log log = LogFactory.getLog( ManagerImpl.class );
 
      public ManagerImpl(TargetServerCore TargetServer) {
            this.TargetServer = TargetServer;
      }
 
      // ------- Target Server Control ---------------------------
      /**
       *StartTargetServer.
       *
       *@throwsManageException
       *             startuperror
       */
      publicvoid startup() throws ManageException {
            try {
                  TargetServer.startup();
            } catch ( CommonException e ) {
                  thrownew ManageException( e.getMessage() );
            }
      }
 
      /**
       *ShutdownTargetServer.
       *
       *@throwsManageException
       *             shutdownerror
       */
      publicvoid shutdown() throws ManageException {
            try {
                  TargetServer.shutdown();
            } catch ( CommonException e ) {
                  thrownew ManageException( e.getMessage() );
            }
      }
     
      publicboolean isStarted() {
            returnTargetServer.isStarted();
      }
 
      /**
       *Reconfigurethelogsetting
       *
       *@paramlogConfig
       */
      publicvoid configureLog(LogConfig logConfig) {
            log.info( "Try to reconfigure log setting" );
            File TargetHome = TargetServer.getHelper().getTargetHome();
            ConfigureHelper.configLog4jByLogConfigBean( logConfig, TargetHome );
      }
 
      // ------- Component Manage-------------------------------
      /**
       *Addcomponent.
       *
       *@paramcomponentInfo
       *@throwsManageException
       *             addfail.
       */
      publicvoid addComponent(AbstractComponentBean componentInfo)
                  throws ManageException {
            try {
                 
                  Component c = TargetServer.getHelper().getComponentFactory().createComponent( componentInfo );
                 
                  TargetServer.getHelper().getComponentMan().addComponent( c );
            } catch ( ComponentManException e ) {
                  log.warn( "Add component failed:" + e.getMessage() );
                  thrownew ManageException( e.getMessage() );
            }
      }
 
      /**
       *Returnallcomponentnames.
       *
       *@returnnotnull
       */
      public String[] getAllComponentNames() {
            returnTargetServer.getHelper().getComponentMan().getAllComponentNames();
      }
 
      /**
       *Returnthecomponentsetting.
       *
       *@paramcomponentName
       *@returnresultnotnull
       *@throwsManageException
       *             componentnotfound
       */
      public AbstractComponentBean getComponentInfo(String componentName)
                  throws ManageException {
            Component component = TargetServer.getHelper().getComponentMan().getComponent( componentName );
            if ( component != null ) {
                  return component.getSettingCopy();
            }
            thrownew ManageException( "Component not found" );
      }
 
      /**
       *Removecomponent.
       *
       *@paramcomponentName
       *@throwsManageException
       *             componentnotfound
       */
      publicvoid removeComponent(String componentName) throws ManageException {
            Component component = TargetServer.getHelper().getComponentMan().removeComponent( componentName );
            if ( component == null ) {
                  log.warn( "Remove component:" + componentName
                              + " failed. component not exist." );
                  thrownew ManageException( "Component not found" );
            }
      }
 
      /**
       *Applynewroutinggraph
       *
       *@deprecateduse{@link #setNewRouting(ComponentConnector[])}instead
       *@paramroutingBeans
       *@returntureonlyifallconnectorisseted
       */
      @Deprecated
      publicboolean setNewRouting(ConnectorBean[] routingBeans) {
            returnTargetServer.getHelper().getComponentMan().setNewRouting( Arrays
                        .asList( ComponentConnector
                                    .connectorBeans2ComponentConnectors( routingBeans ) ) );
      }
 
      /**
       *Applynewroutinggraph
       *
       *@paramroutingBeans
       *@returntureonlyifallconnectorisseted
       */
      publicboolean setNewRouting(ComponentConnector[] routingBeans) {
            returnTargetServer.getHelper().getComponentMan().setNewRouting( Arrays.asList( routingBeans ) );
      }
 
      /**
       *Changecomponentsetting
       *
       *@paramcomponentBean
       *@throwsManageException
       *             componentnotfound
       */
      publicvoid changeComponentSetting(AbstractComponentBean componentBean)
                  throws ManageException {
            try {
                  TargetServer.getHelper().getComponentMan().changeComponentSetting( componentBean );
            } catch ( ComponentManException e ) {
                  log.warn( "Change component setting to:" + componentBean
                              + " , failed." );
                  thrownew ManageException( e.getMessage() );
            }
      }
 
      /**
       *Returntrueifcomponentexsit.
       *
       *@paramcomponentName
       *@returntheresult
       */
      publicboolean isComponentExist(String componentName) {
            Component component = TargetServer.getHelper().getComponentMan().getComponent( componentName );
            if ( component == null ) {
                  returnfalse;
            }
            returntrue;
      }
 
      /**
       *Getthedevicecomponentstatus.Ifthecomponentin
       *<code>componentNames</code>notexist,UNKNOWNwillreturn.
       *
       *@paramcomponentNames
       *@returnresult
       */
      public ConnectionStatus[] getDeviceComponentStatus(String[] componentNames) {
            ConnectionStatus[] result = new ConnectionStatus[componentNames.length];
            int i = 0;
            for (String componentName : componentNames) {
                  ConnectionStatus status = ConnectionStatus.UNKNOWN;
                  Component component = TargetServer.getHelper().getComponentMan().getComponent( componentName );
                  if ( component != null ) {
                        try {
                              DeviceComponent deviceComponent = (DeviceComponent) component;
                              if ( deviceComponent.isConnected() ) {
                                    status = ConnectionStatus.CONNECTED;
                              } else {
                                    status = ConnectionStatus.DISCONNECTED;
                              }
                        } catch ( ClassCastException e ) {
                              // do nothing
                        }
                  }
                  result[i] = status;
                  i++;
            }
            return result;
      }
 
      /**
       *Settheenabledpropertyofcomponent.
       *
       *@paramcomponentName
       *@paramenabled
       *@throwsManageException
       *             componentnotfound.
       */
      publicvoid setComponentEnabledProperty(String componentName,
                  boolean enabled) throws ManageException {
            Component component = TargetServer.getHelper().getComponentMan().getComponent( componentName );
            if ( component == null ) {
                  thrownew ManageException( "Component not found" );
            }
            try {
                  if ( enabled ) {
                        component.startup();
                        TargetServer.getHelper().getComponentMan().resetComponentListener( componentName );
                  } else {
                        component.shutdown();
                  }
            } catch ( ComponentStateException e ) {
                  thrownew ManageException(
                              "Catch a component state exception in changing component state:"
                                          + e.getMessage() );
            }
      }
 
      // ------- Reader Control ----------------------------------
      publicvoid setAutoModeOn(String deviceName) throws ManageException {
            DRFIReaderComponent readerComponent = tryGetReaderComponent( deviceName );
            try {
                  readerComponent.setAutoModeOn();
            } catch ( ComponentImplException e ) {
                  thrownew ManageException( e.getMessage() );
            }
      }
 
      publicvoid setAutoModeOff(String deviceName) throws ManageException {
            DRFIReaderComponent readerComponent = tryGetReaderComponent( deviceName );
            try {
                  readerComponent.setAutoModeOff();
            } catch ( ComponentImplException e ) {
                  thrownew ManageException( e.getMessage() );
            }
      }
 
      public String getVersionNumber(String readerName) throws ManageException {
            // DRFIReaderComponent readerComponent = tryGetReaderComponent(
            // readerName );
            return"TODO";// TODO
            // return readerComponent.( );
      }
 
      publiclong getNumberOfReads(String readerName) throws ManageException {
            DRFIReaderComponent readerComponent = tryGetReaderComponent( readerName );
            return readerComponent.getNumberOfReads();
      }
 
      publiclong[] getNumberOfReads(String[] readerNames) throws ManageException {
            long[] result = newlong[readerNames.length];
 
            int i = 0;
            for (String readerName : readerNames) {
                  DRFIReaderComponent readerComponent = tryGetReaderComponent( readerName );
                  result[i] = readerComponent.getNumberOfReads();
                  i++;
            }
            return result;
      }
 
      public Collection<DRFITag> readTags(String readerName)
                  throws ManageException {
 
            DRFIReaderComponent readerComponent = tryGetReaderComponent( readerName );
            try {
                  return readerComponent.readTags();
            } catch ( ComponentImplException e ) {
                  thrownew ManageException( e.getMessage() );
            }
      }
 
      public Collection<DRFITag> readTags(String readerName, int antennaSequenceNo)
                  throws ManageException {
            DRFIReaderComponent readerComponent = tryGetReaderComponent( readerName );
            try {
                  return readerComponent.readTags( antennaSequenceNo );
 
            } catch ( ComponentImplException e ) {
                  thrownew ManageException( e.getMessage() );
            }
      }
 
      public Collection<DRFITag> readTags(String readerName,
                  int[] antennaSequenceNo) throws ManageException {
            DRFIReaderComponent readerComponent = tryGetReaderComponent( readerName );
            try {
                  return readerComponent.readTags( antennaSequenceNo );
            } catch ( ComponentImplException e ) {
                  thrownew ManageException( e.getMessage() );
            }
      }
 
      publicvoid writeTag(String deviceName, String writeFlag, String epc,
                  String userData, String killCode, int antennaSequenceNo)
                  throws ManageException {
            DRFIReaderComponent readerComponent = tryGetReaderComponent( deviceName );
            try {
                  readerComponent.writeTag( writeFlag, epc, userData, killCode,
                              antennaSequenceNo );
            } catch ( ComponentImplException e ) {
                  thrownew ManageException( e.getMessage() );
            }
      }
 
      publicvoid killTag(String deviceName, String uri, String killCode,
                  int antennaSequence) throws ManageException {
            DRFIReaderComponent readerComponent = tryGetReaderComponent( deviceName );
            try {
                  readerComponent.killTag( uri, killCode, antennaSequence );
            } catch ( ComponentImplException e ) {
                  thrownew ManageException( e.getMessage() );
            }
      }
 
      publicvoid setReadPower(String deviceName, int powerPercent)
                  throws ManageException {
            DRFIReaderComponent readerComponent = tryGetReaderComponent( deviceName );
            try {
                  readerComponent.setReadPower( powerPercent );
            } catch ( ComponentImplException e ) {
                  thrownew ManageException( e.getMessage() );
            }
      }
 
      private DRFIReaderComponent tryGetReaderComponent(String componentName)
                  throws ManageException {
            Component component = TargetServer.getHelper().getComponentMan().getComponent( componentName );
            if ( component == null ) {
                  thrownew ManageException( "Componet not found" );
            }
            try {
                  DRFIReaderComponent readerComponent = (DRFIReaderComponent) component;
                  return readerComponent;
            } catch ( ClassCastException e ) {
                  thrownew ManageException( "Componet is not a DRFIReader" );
            }
      }
 
      public Object sendEvent2Component(String targetCompName, Object event)
                  throws ManageException {
            try {
                  return sendComponentEvent2Component( targetCompName, new ConnectorEndpoint( "", 0 ) ,event );
            } catch ( ManageException e1 ) {
                  thrownew ManageException( e1.getMessage(), e1 );
            }
      }
 
      public Object sendComponentEvent2Component(String targetCompName,
                  ConnectorEndpoint srcCompInfo, Object event) throws ManageException {
            Component component = TargetServer.getHelper().getComponentMan().getComponent( targetCompName );
            if ( component == null ) {
                  thrownew ManageException( "Componet not found" );
            }
            try {
                  ComponentEvent<Object> compEvent = new ComponentEvent<Object>( srcCompInfo.getComponentName(), System
                              .currentTimeMillis(), srcCompInfo.getComponentPort(), Arrays.asList( event ) );
                  return component.onEvent( compEvent );
            } catch ( ComponentStateException e1 ) {
                  thrownew ManageException( "Component is stoped" );
            }
      }
 
      public List<ComponentConnector> getAllConnectors() {
            returnnew ArrayList<ComponentConnector>( TargetServer.getHelper().getComponentMan().getAllConnectors() );
      }
 
      publicvoid addConnector(ComponentConnector connector) {
            TargetServer.getHelper().getComponentMan().addConnector( connector );
      }
 
      publicvoid removeConnector(ComponentConnector connector) {
            TargetServer.getHelper().getComponentMan().removeConnector( connector );
      }
 
}
 
 
现在有两个要求:
1.        在每个方法调用前检查方法调用的状态要求是否已经达到。
2.        状态加锁
 
 

publicclass LockedManagerFactory {
      publicstatic CoreManager decorate( CoreManager man, Lock lock ) {
            MyInvocationHandler handler = new MyInvocationHandler( man, lock );
            Object result = Proxy.newProxyInstance( LockedManagerFactory.class
                        .getClassLoader(), new Class[] { CoreManager.class }, handler );
            return (CoreManager) result;
      }
}
 
publicclass MyInvocationHandler implements InvocationHandler {
 
      private CoreManager impl;
     
      private Lock lock;
     
      private ArrayList<Method> notLockMethods;
      private ArrayList<Method> noStartedNeedMethods;
     
      public MyInvocationHandler(CoreManager impl, Lock lock) {
            this.impl = impl;
           
            notLockMethods = new ArrayList<Method>();
            try {
                  notLockMethods.add( CoreManager.class.getMethod( "startup", new Class[0] ) );
                  notLockMethods.add( CoreManager.class.getMethod( "shutdown", new Class[0] ) );
            } catch ( Exception e ) {
                  thrownew RuntimeException( e );
            }
           
            noStartedNeedMethods = new ArrayList<Method>();
            try {
                  noStartedNeedMethods.add( CoreManager.class.getMethod( "isStarted", new Class[0] ) );
                  noStartedNeedMethods.add( CoreManager.class.getMethod( "startup", new Class[0] ) );
                  noStartedNeedMethods.add( CoreManager.class.getMethod( "shutdown", new Class[0] ) );
            } catch ( Exception e ) {
                  thrownew RuntimeException( e );
            }
           
            this.lock = lock;
      }
     
      public Object invoke(Object proxy, Method method, Object[] args)
                  throws Throwable{
                  if( !noStartedNeedMethods.contains( method ) ) {//Target Server started needed
                        lock.lock();
                        try {
                              if( impl.isStarted() == false ) {//TargetServer stoped
                                    thrownew ManageException("TargetServer Stoped");
                              }
                              return invoke(method , args );
                        }finally {
                              lock.unlock();
                        }
                  }
//                Target Server started not needed
                  if( notLockMethods.contains( method ) ) {
                        return invoke(method , args );
                  }
                  else {
                        lock.lock();
                        try {
                              return invoke(method, args );
                        }finally {
                              lock.unlock();
                        }
                  }
      }
     
      private Object invoke(Method method, Object[] args) throws Throwable {
            Object returnedResult = null;
            try {
                   returnedResult = method.invoke( impl, args );
            } catch ( InvocationTargetException e ) {
                  throw e.getCause();
            } catch( Throwable e ) {
                  throw e;
            }
            returnreturnedResult;
      }
     
}
 
 
现在,客户代码将会是:
 
 

/**
 *TheTargetserverobject
 *
 */
publicclass TargetServerCore {
 
      privatestaticfinal Log log = LogFactory.getLog( TargetServerCore.class );
 
      privatebooleanstarted;
 
      private TargetServerCoreHelper helper;
 
      private Collection<TargetServerLifeCycleListener> listeners;
     
      private Lock readLock;
 
      private Lock writeLock;
     
      private CoreManager manager;
     
      public TargetServerCore() {
            started = false;
            listeners = new ArrayList<TargetServerLifeCycleListener>();
            ReadWriteLock rwLock = new ReentrantReadWriteLock();
            readLock = rwLock.readLock();
            writeLock = rwLock.writeLock();
            manager = new ManagerImpl( this );
            manager = LockedManagerFactory.decorate( manager, readLock );
            manager = InvokeLogProxyFactory.decorate( manager, Level.DEBUG, Logger.getLogger( TargetServerCore.class ) );
      }
     
      public CoreManager getManager() {
            returnmanager;
      }
     
      public TargetServerCoreHelper getHelper() {
            returnhelper;
      }
     
      publicfinalboolean isStarted() {
            returnstarted;
      }
 
      /**
       *Returnwhensucessfulstaruped.
       *
       *@throwsCommonException
       *             errorappear.
       */
      publicvoid startup() throws CommonException {
            writeLock.lock();
            try {
                  doStartup( true );
            } finally {
                  writeLock.unlock();
            }
      }
 
      /**
       *Returnwhensuccessfulshutdowned.
       *
       *@throwsCommonException
       *             errorappear.
       */
      publicvoid shutdown() throws CommonException {
            writeLock.lock();
            try {
                  doShutdown();
            } finally {
                  writeLock.unlock();
            }
      }
 
      /**
       *addListener.
       *
       *@paramlistener
       */
      publicvoid addListener(TargetServerLifeCycleListener listener) {
            synchronized (listeners) {
                  this.listeners.add( listener );
            }
      }
 
      /**
       *removeListener.
       *
       *@paramlistener
       */
      publicvoid removeListener(TargetServerLifeCycleListener listener) {
            synchronized (listeners) {
                  this.listeners.remove( listener );
            }
      }
 
      privatevoid doStartup(boolean reconfigLog) throws CommonException {
 
            if ( started ) {
                  thrownew CommonException(
                              "Target Server already startuped, can't startup twice" );
            }
 
            helper = new TargetServerCoreHelper( this );
 
            helper.locateFile();
 
            // Configure log by default log setting
            if ( reconfigLog ) {
                  File configFile = new File( helper.TargetConfigHome,
                              "Target_default_log4j_setting.xml" );
                  log.info( "Configuring log4j by default configure file:"
                              + configFile );
                  ConfigureHelper.configLog4jByFile( configFile, helper.TargetHome );
            }
 
            helper.loadProperties();
 
            helper.loadConfig();
 
            if ( reconfigLog ) {
                  // Configure log by CustomizeLog4jSettingFile or TargetServer config
                  helper.reconfigLog4J();
            }
 
            helper.updatePlugin();
 
            helper.buildPluginManager();
            helper.buildComponentRelated();
            helper.initSavedComponents();
 
            started = true;
 
            helper.startupVMHolder();
 
      }
 
      privatevoid doShutdown() throws CommonException {
            if ( started == false ) {
                  thrownew CommonException(
                              "Target Server haven't startup, can't be shutdown" );
            }
            // shutdown Component Manager
            helper.componentMan.shutdownAllComponent();
 
            started = false;
 
            helper.serverVMHolder.notifyEnd();
           
            helper = null;
           
            notifyAllListenerStateChanged( TargetServerState.STOPED, "" );
 
      }
 
      void notifyAllListenerStateChanged(TargetServerState state, String step) {
            synchronized (listeners) {
                  for( TargetServerLifeCycleListener listener : listeners ) {
                        listener.stateChanged( state, step );
                  }
            }
      }
 
}
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值