Guice如何将单例和非单例注入多个线程

时间:2013-02-08 17:48:02

标签: java multithreading concurrency singleton guice

说我有课:

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注入一个ThreadFactory,然后用于创建和执行MyTask个实例通过。而且,由于它是一个缓存池,它只在需要一个新线程时创建一个新线程但不可用。

我想知道当我们将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个正在运行的线程。由于我们没有要求Guice将Fizz es作为单例注入,我假设每个线程都有自己的注入FizzImpl副本,我们不必添加任何synchronize - 类型代码,以防止3 FizzImpl发生冲突并导致线程问题。

但是当我们让Guice将FizzImpl注入单身时会发生什么?!?现在,在MyAppModule中:

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

如果Guice只提供1个FizzImpl的全局单例实例,那么FizzImpl“副本”的下游分支是什么(如果这是正确的话) 3个产生的线程?有哪些陷阱需要注意?有什么方法可以解决这些陷阱?提前谢谢。

1 个答案:

答案 0 :(得分: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() { ... }
}

如果你将一个Singleton标志放到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);
    }
}

希望它会有所帮助!