1

我正在构建一个程序,该程序需要构建一些需要如此密集计算才能创建的对象,我最聪明的课程是将它们构建在自己的专用线程中,而主线程则不断研究其他事物,直到对象被需要。

所以我想创建一个专门用于在自己的线程中创建自定义对象的特殊类。像这样:

public abstract class DedicatedThreadBuilder<T> {

    private T object;

    public DedicatedThreadBuilder() {
        DedicatedThread dt = new DedicatedThread(this);
        dt.start();
    }

    private void setObject(T i) {
        object = i;
    }

    protected abstract T constructObject();

    public synchronized T getObject() {
        return object;
    }

    private class DedicatedThread extends Thread {

        private DedicatedThreadBuilder dtb;

        public DedicatedThread(DedicatedThreadBuilder builder){
            dtb = builder;
        }

        public void run() {
            synchronized(dtb) {
                dtb.setObject(dtb.constructObject());
            }
        }

    }

}

我唯一担心的是,这种机制只有在主线程(即构造DedicatedThreadBuilder的线程)在DedicatedThreadBuilder构建完成之前具有同步锁时才能正常工作,因此会阻止DedicatedThread构建产品对象的尝试直到完成DedicatedThreadBuilder的构建。为什么?因为DedicatedThreadBuilder的子类无疑需要使用参数构造,所以需要将它们传递到它们自己的私有存储中,以便它们可以在constructObject()过程中使用。

例如

public class JellybeanStatisticBuilder extends DedicatedThreadBuilder<JellybeanStatistics> {

    private int greens;
    private int blacks;
    private int yellows;

    public JellybeanStatisticBuilder(int g, int b, int y) {
        super();
        greens = g;
        blacks = b;
        yellows = y;
    }

    protected JellybeanStatistics constructObject() {
        return new JellybeanStatistics(greens, blacks, yellows);
    }

}

这只有在对象被其他线程阻塞直到它完全构造之后才能正常工作。否则,DedicatedThread可能会在分配必要的变量之前尝试构建对象。

那么Java就是这样工作的吗?

4

3 回答 3

2

我认为您想要的是拥有某种同步的工厂类:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

public class SyncFactory<T> {    
    // alternatively, use newCachedThreadPool or newFixedThreadPool if you want to allow some degree of parallel construction
    private ExecutorService executor = Executors.newSingleThreadExecutor();

    public Future<T> create() {        
        return executor.submit(() -> {
            return new T();
        });
    }
}

现在,您可以将在准备好T之前可能需要发生的用法替换为,并且可以选择调用其方法以阻塞直到它准备好、设置超时或调用以检查构造而不阻塞。此外,您可能希望工厂调用回调或发布事件以在主线程完成构建时通知主线程,而不是轮询 Future。TFuture<T>Future.get()Future.isDone()

于 2018-11-08T18:55:19.377 回答
0

如果如果)这是真的需要(首先考虑一个)......

你所追求的总体想法是可行的,但你的代码令人困惑,无论如何,乍一看,它似乎可能行不通。这种可以破坏事物的复杂性是在这条道路上进行双重思考甚至三重思考的一个很好的理由。

我立即发现的主要问题是您只创建了一个对象实例。如果这是一个只在另一个线程上创建东西的工厂,那么DedicatedThread应该在 's 中调用DedicatedThreadBuilder's constructObject,而不是在其构造函数中调用。

另一方面,如果您实际上打算DedicatedThreadBuilder只创建 1 个实例T,那么这种抽象似乎没有必要……只需将DedicatedThread' 的行为移出DedicatedThreadBuilder,因为DedicatedThreadBuilder似乎并没有做任何额外的事情。

其次,一件小事并非不正确,因为它只是不必要的:你有一个内部类,你将外部类的一个实例传递给它的构造函数(即,DedicatedThread的构造函数引用它的 parent DedicatedThreadBuilder)。这是不必要的,因为非静态内部类已经链接到它们的外部类,因此内部类可以引用外部类而无需额外引用它。

第三,如果您将行为移出构造函数并移到单独的方法中,那么您可以同步它。就个人而言,我本来应该constructObject是启动该过程的东西,以便调用dtb.constructObject()开始对象的创建,并在完成时constructObject自行设置object = newlyCreatedThing。然后,您可以根据需要同步该方法,或者做任何事情,而不必担心构造函数的行为可能不符合您的要求-在我看来,您通常不必担心构造函数可能会产生一些奇怪的副作用。

第四,你有没有办法知道对象什么时候准备好并且可以获取?您可能希望为此添加一些机制,例如观察者或其他回调。

于 2018-11-08T18:47:25.170 回答
0

问题是您在构建子类之前使用它。它与多线程没有任何关系。如果您constructObject直接从DedicatedThreadBuilder构造函数调用,那将同样糟糕。

与您所拥有的最接近的合理实现只是提供DedicatedThreadBuidler一个单独的start()方法,该方法应在构造对象后调用。

或者你可以让它扩展Thread并使用 Thread 方法。

或者你可以实现它Runnable,这样你就可以将它与 aThread或 anExecutor或其他任何东西一起使用。

于 2018-11-08T19:03:51.800 回答