2016-04-28 52 views
1

我正在研究使用LDAP服务器作为永久存储的多线程应用程序。我创建了以下服务类来启动和停止LDAP服务需要的时候:在Java中安全地启动/停止服务实例

public class LdapServiceImpl implements LdapService { 

    public void start() { 
     if (!isRunning()) { 
      //Initialize LDAP connection pool 
     } 
    } 

    public void stop() { 
     if (isRunning()) { 
      //Release LDAP resources 
     } 
    } 

    private boolean isRunning() { 
     //What should go in here? 
    } 

} 

我们目前使用谷歌吉斯注入服务实现的单一实例:

public class ServiceModule extends AbstractModule { 

    @Override 
    protected void configure() { 
    } 

    @Provides @Singleton 
    LdapService providesLdapService() { 
     return new LdapServiceImpl(); 
    } 

} 

这样,我们才能在应用程序启动时设置连接池,对连接执行某些操作,然后在应用程序关闭时释放资源:

public static void main(String[] args) throws Exception { 
    Injector injector = Guice.createInjector(new ServiceModule()); 

    Service ldapService = injector.getInstance(LdapService.class)); 
    ldapService.start(); 
    addShutdownHook(ldapService); 

    //Use connections 

} 

private static void addShutdownHook(final LdapService service) { 
    Runtime.getRuntime().addShutdownHook(new Thread() { 
     @Override 
     public void run() { 
      service.stop(); 
     } 
    }); 
} 

我面临的问题是我想确保服务只启动/停止一次。为此,我在服务实现中添加了一个“isRunning()”方法,但我不确定如何实现它。

考虑到应用程序是多线程的,并且我的Service实例是单例,实现“isRunning()”方法的最佳方法是什么?

此外,有没有更好/更干净的方式来实现这一目标?

在此先感谢。

回答

2

如果LdapServiceImpl是一个单例,并且您担心多个线程同时调用start或stop方法,您应该可以简单地将synchronized关键字添加到start和stop方法中。在这一点上,你可以使用一个简单的布尔标志来存储当前的运行状态,并且只要所有访问该状态的方法都是同步的,你就应该是安全的。

public class LdapServiceImpl implements LdapService { 

    private boolean isRunning = false; 

    public synchronized void start() { 
     if (!isRunning()) { 
      //Initialize LDAP connection pool 
      isRunning = true; 
     } 
    } 

    public synchronized void stop() { 
     if (isRunning()) { 
      //Release LDAP resources 
      isRunning = false; 
     } 
    } 

    private boolean isRunning() { 
     return isRunning; 
    } 
} 
+0

错字:“同步”,但是,这应该工作。我可能会避免使用'isRunning'方法并直接使用标志,但这应该没问题。 –

+0

@KedarMhaswade感谢您指出错字:)而且,isRunning方法完全是多余的,我只是想在原始问题的上下文中展示这个例子。 – djmorton

1

djmorton的答案是绝对正确的,你会很安全的实现它,不管它是否为任务分配或自由时间的项目。

话虽如此,这里有另一种解决方案 - 有人可能会说它比安全和简单的解决方案有一些优势,但我不会声称。我添加它只是为了展示另一种方法(并且因为在出现问题时抛出代码很有趣)。

public static class LdapServiceImpl implements LdapService { 

    private static final int STOPPED = 0; 
    private static final int STARTING = 1; 
    private static final int STOPPING = 2; 
    private static final int STARTED = 3; 

    private AtomicInteger serviceState = new AtomicInteger(STOPPED); 

    public void start() { 
     if (serviceState.compareAndSet(STOPPED, STARTING)) { 
     System.out.println("Starting by " + Thread.currentThread().getName()); 
     // Initialize LDAP resources 
     boolean startSuccess = serviceState.compareAndSet(STARTING, STARTED); 
     // Handle startSuccess == false, if that somehow happened 

     } 
    } 

    public void stop() { 
     if (serviceState.compareAndSet(STARTED, STOPPING)) { 
     System.out.println("Stopping by " + Thread.currentThread().getName()); 
     // Release LDAP resources 
     boolean stopSuccess = serviceState.compareAndSet(STOPPING, STOPPED); 
     // Handle stopSuccess == false, if that somehow happened 
     } 
    } 

} 
+0

感谢您的回答Dimitar。尽管我选择了“简单”的方法,但很高兴看到更精细的替代方案。 –