【问题标题】:How to Thread a complex Model class to provide synchronization with a Controller class?如何线程化复杂的模型类以提供与控制器类的同步?
【发布时间】:2012-03-15 19:11:01
【问题描述】:

如何根据复杂模型的一部分是否产生正确的标志在控制器中进行?

控制器类正在播放 Midi 序列队列,同时持有通过用户按钮动态更新的模型类的实例。在 Midi 队列结束后,控制器需要与模型同步,以检查用户是否进行了一定数量的条目,然后再继续更新界面并移动到应用程序的下一部分。除了用户按钮按下的 ArrayList 之外,Model 还表示相当多的其他数据,因此挑战在于如何最好地划分同步部分。

现在,我正在尝试的模式类似于以下,由于控制器和模型之间的嵌套类访问,它不起作用:

//Controller
...
Thread entriesCoordination = new Thread( new Model.InnerClass);
entriesCoordination.start();

Thread t = new Thread (this);
t.run();

...
//in runnable nested class in controller
private Model.InncerClass c = new Model.InnerClass();
public void run() {
    synchronized( c) { 
        while (!c.hasFinishedEntries()){
            try{
                c.wait();
            } catch (InterruptedException ignore{}
            }
        }
    }
    //Midiqueue completed and Entries finished
}
//in Model
//in runnable nested class in Model
public synchronized boolean hasFinishedEntries() {
    return fIsFinishedWithEntries;
}

public void run() {
    while(true) {
        try{
            synchronized(this) {
                try{
                    if(entriesArray.size() == max_size) {
                        fIsFinishedWithEntries = true;
                        notifyAll();
                    } else {...}
                }
            }
        }
    }
}

此外,这似乎很浪费,因为它基本上意味着我需要创建一个线程并在用户可以进行这些按钮选择的整个持续时间内并行运行 Model 的内部类,而不是当我知道 Midi 队列已经结束时,只会轮询 Model

Controller 类到synchronizeModel 类中的一个标志的设计模式是什么,而不必为了处理同步而在模型中创建内部类。

【问题讨论】:

    标签: java model-view-controller design-patterns concurrency inner-classes


    【解决方案1】:

    我认为正确的做法是使用AtomicBoolean 并在每个线程对象上定义方法来获取和设置布尔值。

    Model.InnerClass 将被更改为添加 AtomicBoolean 并将 getter 更改为不同步。

    private final AtomicBoolean fIsFinishedWithEntries = new AtomicBoolean();
    public boolean hasFinishedEntries() {
        return fIsFinishedWithEntries.get();
    }
    

    在 run 方法中,需要将完成的布尔值设置为 true。

    public void run() {
        while(true) {
                if (entriesArray.size() == max_size) {
                    synchronized (this) {
                        fIsFinishedWithEntries.set(true);
                        notifyAll();
                    }
                } else {...}
            }
        }
    }
    

    如果您不止一次这样做,您需要将它放在false 某个地方。

    现在,我正在尝试的模式类似于以下,由于控制器和模型之间的嵌套类访问,它不起作用:

    您需要首先创建您的 Model.InnerClass 实例并将其注入到您的控制器线程中。将hasFinishedEntries() 设为静态是丑陋的,因此您可以在控制器中调用:

    private Model.InnerClass innerClass;
    public ControllerThread(Model.InnerClass innerClass) {
        this.innerClass = innerClass;
    }
    ...
    public void run() {
        synchronized (innerClass) {
            while (!innerClass.hasFinishedEntries()){
                innerClass.wait();
            }
        }
    }
    

    如何在不同步整个模型类的情况下访问条目是否完成?

    您显然可以在想查看队列是否结束时轮询hasFinishedEntries()。我不确定没有线程的更好方法。有什么方法可以设置一个 UI 事件来每隔一段时间检查一次条件吗?

    【讨论】:

    • 谢谢格雷。我更新了问题以在控制器中创建Model.InnerClass,正如您所建议的,@Gray。我不认为我真的需要一个原子的 get,set,put 布尔值,只是因为控制器总是在那里获取而模型总是放置,这不会为交错放置之类的线程干扰留下任何空间。总体而言,您是说通过这些嵌套的“可运行”内部类执行此操作是向模型的某些部分公开同步,同时将其与整个模型类完全分离的方式?
    • 您正在寻找一种方法来查看事情是否在没有同步的情况下完成。如果您总是要等待,那么我同意 AtomicBoolean 是不必要的。
    • 嵌套Runnable 内部类很好。由于内部对象的可见性,您在内部类上同步时遇到问题。有很多方法可以解决这个问题。一种方法是将hasFinished() 方法放在调用内部类的外部类中。您还可以将内部类锁定在其他类可以看到的外部类中的 static final Object lockObject = new Object(); 上。但是外部方法调用更干净。
    猜你喜欢
    • 2012-08-12
    • 2014-09-09
    • 1970-01-01
    • 2019-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-20
    相关资源
    最近更新 更多