3

クラスがあるとします:

public class MyTask implements Runnable {
    @Inject
    private Fizz fizz;

    // Getters and setters for 'fizz'.

    @Override
    public void run() {
        if(fizz.alleviatesBuzz())
            doA();
        else
            doB();
    }

    private void doA() { ... }

    private void doB() { ... }
}

そして、私は別のクラスを持っています:

public class MyTaskDispatcher {
    @Inject
    private ThreadFactory threadFactory;

    private Executor executor;

    // Getter and setter for 'threadFactory'.

    public void dispatch(MyTask task) {
        if(executor == null)
            executor = Executors.newCachedThreadPool(threadFactory);

        executor.submit(task);
    }
}

そのため、 Guice は を注入MyTaskし、渡されたインスタンスの作成と実行に使用されるFizzも注入MyTaskDispatcherします。また、キャッシュされたプールであるため、新しいスレッドが必要であるが使用できない場合にのみ新しいスレッドを作成します。ThreadFactoryMyTask

Fizzシングルトンまたは非シングルトンとして注入する場合、マルチスレッド環境で Guice がどのように「動作」するのか疑問に思っています。

たとえば、非シングルトンから始めましょう。

public class MyAppModule extends AbstractModule {
    @Override
    public void configure() {
        bind(Fizz.class).to(FizzImpl.class);

        // I don't think the functionality of MyThreadFactory
        // really matters for the sake of this question.
        bind(ThreadFactory.class).to(MyThreadFactory.class);
    }

    @Provides
    FizzImpl providesFizz() {
        return new FizzImpl(true, Buzz.ALWAYS, 35);
    }

    // I *believe* we always want the ThreadFactory to be singleton,
    // because all of the threads spawn from it and its executor.
    @Provides @Singleton
    ThreadFactory providesThreadFactory() {
        return new MyThreadFactory(12);
    }
}

ここで、アプリがしばらく実行されていて、3 つの個別MyTaskの が送信されたため、3 つの実行中のスレッドが存在するとします。es をシングルトンとして注入するように Guice に依頼しなかったのでFizz、各スレッドには注入された の独自のコピーがあり、3 つの s が衝突してスレッドの問題が発生するのを防ぐために -type コードをFizzImpl追加する必要はないと仮定します。synchronizeFizzImpl

しかし、Guice をFizzImplシングルトンとして注入するとどうなるでしょうか?!? 今、でMyAppModule

    @Provides @Singleton
    FizzImpl providesFizz() {
        return new FizzImpl(true, Buzz.ALWAYS, 35);
    }

Guice が の 1 つのグローバルなシングルトン インスタンスのみを提供する場合、生成された 3 つのスレッドのそれぞれの内部で、その「コピー」FizzImplの下流への影響は何ですか (それが正しい言葉である場合)。FizzImpl注意すべき落とし穴とは?これらの落とし穴に対抗する方法は何ですか? 前もって感謝します。

4

1 に答える 1

1

いいえ、Fizz は MyTask インスタンスで作成され、複数のスレッド呼び出しを実行しても保持されます。スレッドごとに Fizz のコピーが必要な場合は、怠惰な方法で行う必要があります。

public class MyTask implements Runnable {
    @Inject
    private Provider<Fizz> fizzProvider;

    // Getters and setters for 'fizz'.

    @Override
    public void run() {
        Fizz fizz = fizzProvider.get();
        if(fizz.alleviatesBuzz())
            doA();
        else
            doB();
    }

    private void doA() { ... }

    private void doB() { ... }
}

シングルトン フラグを Fizz バインディングに設定すると、プロバイダーは fizzProvider.get() を呼び出したときに同じインスタンスを返すため、すべてのスレッドが同じインスタンスを持つことになります。非シングルトンにしておく必要があります。

また、モジュールが間違っています。両方ではなく、メソッドまたは暗黙のバインディングを使用する必要があります。また、インスタンスを提供してそのインターフェースを注入することもできません。

public class MyAppModule extends AbstractModule {
    @Override
    public void configure() {
        bind(Fizz.class).to(FizzImpl.class);
        //or bind(Fizz.class).toInstance(new FizzImpl(true, Buzz.ALWAYS, 35)); //Singleton!!
        //or bind(Fizz.class).toProvider(new Provider<Fizz>() {
        //      @Override
        //      public Subject get() {
        //        return new FizzImpl(true, Buzz.ALWAYS, 35);
        //      }
        //    });

        // I don't think the functionality of MyThreadFactory
        // really matters for the sake of this question.
        bind(ThreadFactory.class).to(MyThreadFactory.class);
    }
}

また

public class MyAppModule extends AbstractModule {
    @Override
    public void configure() {
    }

    @Provides
    Fizz providesFizz() {
        return new FizzImpl(true, Buzz.ALWAYS, 35);
    }

    // I *believe* we always want the ThreadFactory to be singleton,
    // because all of the threads spawn from it and its executor.
    @Provides @Singleton
    ThreadFactory providesThreadFactory() {
        return new MyThreadFactory(12);
    }
}

それが役立つことを願っています!

于 2013-07-26T11:56:09.883 に答える