2016-04-28 82 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。儘管我選擇了「簡單」的方法,但很高興看到更精細的替代方案。 –