我是多线程的开端。我最近开始写类似多线程观察器的东西。我需要澄清一下。
假设我正在与Subject合作,并且我正在更改其状态。然后必须通知观察者(例如GUI窗口小部件),以便他们可以执行update()
方法。
我有一个问题:我如何处理许多观察员执行的getValue()
?如果它只是某个变量的吸气剂,我是否必须在新线程中运行它?需要锁定吗?
或者也许有一种方法可以将这些新值发送到GUI线程,然后让其中的小部件访问这些值。再说一次,这可能是一个循环,还是我必须为每个小部件创建另一个线程才能获得这些值?
答案 0 :(得分:0)
这是一个很难的主题。以下几件事将为您提供指导和帮助。
拥抱最终的一致性。当一个对象在一个线程上更新时,其他对象将收到更改通知并最终最终更新到正确状态。不要试图使所有内容始终保持同步。不要指望一切都保持最新状态。设计系统以处理这些情况。查看this视频。
使用不变性,尤其是对于集合。从多个线程读取和写入集合可能会导致灾难。不要这样使用不可变的集合或使用快照。基本上,将从多个线程调用的一个对象将返回集合状态的快照。当收到更改通知时,阅读器(在您的情况下为GUI)将请求新状态的快照并进行相应更新。
设计丰富的Models。不要使用只有setters
和getters
的{{3}},而要让其他人来操纵它们。让 模型 保护其数据并提供其状态查询。不要从对象的属性返回可变对象。
传递带有更改通知的描述更改的数据。这样,读取器(GUI)可以仅从更改数据同步其状态,而不必读取目标对象。
划分责任。让GUI知道它是单线程的,并从后台接收到通知。不要在您的 模型 中添加知识,这些知识将在后台线程上进行更新,并且不要知道它是从GUI调用的,并承担将更改请求发送到的责任。一个特定的线程。 模型 不应该在意这样的东西。它引发通知,并让订户按照需要的方式处理它们。让GUI知道更改通知将在后台接收,因此可以将其传输到UI线程。
选中AnemicModels。它描述了执行多线程的不同方法。
您没有显示任何代码或指定的语言,因此,我将为您提供一个使用类似Java / C#语言的伪代码示例。
public class FolderIcon {
private Icon mIcon;
public Icon getIcon() { return mIcon; }
public FolderIcon(Icon icon) {
mIcon = icon;
}
}
public class FolderGUIElement : Observer {
private Folder mFolder;
private string mFolderPath;
public FolderGUIElement(Folder folder) {
mFolder = folder;
mFolderPath = mFolder.getPath();
folder.addChangeListener(this);
}
public void onSubjectChanged(change c) {
if(c instanceof PathChange) {
dispatchOnGuiThread(() => {
handlePathChange((PathChange)change);
});
}
}
handlePathChange(PathChange change) {
mFolderPath = change.NewPath;
}
}
public class Folder : Subject {
private string mPath;
private FolderIcon mIcon;
public string getPath() { return mPath; }
public FolderIcon getIcon() { return mIcon; }
public void changePath(string newPath) {
mPath = patnewPath;
notifyChanged(new PathChange(newPath));
}
public void changeIcon(FolderIcon newIcon) {
mIcon = newIcon;
notifyChanged(new IconChange(newIcon));
}
}
请注意示例中的几件事。
我们正在使用 文件夹 中的不可变对象。这意味着GUI元素无法获取Path
或FolderIcon
的值并对其进行更改,从而影响 文件夹 。更改图标时,我们将创建一个全新的 FolderIcon 对象,而不是修改旧的对象。 文件夹 本身是可变的,但是它使用不可变的对象作为其属性。如果需要,可以使用完全不变的对象。混合方法效果很好。
当我们收到变更通知时,我们会从 PathChange 中读取 NewPath 。这样,我们不必再次调用 文件夹 。
我们拥有changePath
和changeIcon
方法,而不是setPath
和setIcon
。这样可以更好地捕获我们的操作意图,从而为我们提供模型行为,而不仅仅是袋getters
和setters
。
如果您还没有读过this video,我强烈推荐您。这与多线程无关,而与如何设计丰富的模型有关。每个开发人员都应该在我的书籍清单中阅读。 DDD中的概念为Domain Driven Design。它是不可变的,并提供了一种实现模型的好方法,在多线程系统中尤其有用。