2016-04-28 11 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? 
    } 

} 

我々は現在、シングルトンインスタンスとしてサービスの実装を注入するには、Google Guiceのを使用します。

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()"メソッドを追加しましたが、実装方法はわかりません。

アプリケーションがマルチスレッドであり、サービスインスタンスがシングルトンであることを考慮して、「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

Typo: 'synchronized'ですが、これはうまくいくはずです。おそらく 'isRunning'メソッドを避けてフラグを直接使うのですが、これは大丈夫です。 –

+0

@KedarMhaswade typoを指摘してくれてありがとう:)そして、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

ディミタールにお返事ありがとうございます。私は「シンプルな」アプローチを選択したにもかかわらず、より精巧な選択肢を見てうれしいです。 –

関連する問題