我有一个实用程序类如下:
public class MetaUtility {
private static final SparseArray<MetaInfo> metaInfo = new SparseArray<>();
public static void flush() {
metaInfo.clear();
}
public static void addMeta(int key, MetaInfo info) {
if(info == null) {
throw new NullPointerException();
}
metaInfo.append(key, info);
}
public static MetaInfo getMeta(int key) {
return metaInfo.get(key);
}
}
这个类非常简单,我希望有一个“中心”容器可以跨类/活动使用
问题在于线程化
现在它被填充(即addMeta
被调用)只在代码中的一个位置(不在UI线程中)并且不会改变。
getter由UI线程访问,在某些情况下由后台线程访问
仔细查看代码我不认为我最终会遇到后台线程会向稀疏数组中添加元素的情况,而其他一些线程会尝试访问它。
但是,除非他非常了解这些代码,否则这对于有人知道是非常棘手的
我的问题是,我如何设计我的类,以便我可以安全地从包括UI线程在内的所有线程中使用它?
我不能只是添加一个synchronized或make it阻止,因为这会阻止UI线程。我该怎么办?
答案 0 :(得分:1)
你应该只对你的对象进行同步,因为你的类现在只是一个围绕SparseArray的包装类。如果存在线程级别阻塞问题,那么它们可能是因为在项目的其他部分中滥用此对象(我认为类只考虑它只公开公共静态方法)。
答案 1 :(得分:1)
首次拍摄可以synchronized
。
@Jim线程调度延迟怎么样?
Android调度程序基于Linux,它被称为完全公平的调度程序(CFS)。它是“公平的”,因为它试图平衡任务的执行,不仅基于线程的优先级,而且还通过跟踪给予线程的执行时间量。
如果您看到“跳过的xx帧!应用程序可能在其主线程上做了太多工作”,那么需要进行一些优化。
答案 2 :(得分:1)
如果你有无竞争锁定,你不应该害怕使用synchronized
。在这种情况下,锁应该是thin
,这意味着它不会将阻塞的线程传递给OS
调度程序,但会尝试再次获取锁定后的几条指令。但是,如果您仍想编写非阻塞实现,那么您可以使用AtomicReference
来保存SparseArray<MetaInfo>
数组,并使用CAS
进行更新。
代码可能像这样:
static AtomicReference<SparseArray<MetaInfo>> atomicReference = new AtomicReference<>();
public static void flush() {
atomicReference.set(new SparseArray<MetaInfo>);
}
public static void addMeta(int key, MetaInfo info) {
if(info == null) {
throw new NullPointerException();
}
do {
SparseArray<MetaInfo> current = atomicReference.get();
SparseArray<MetaInfo> newArray = new SparseArray<MetaInfo>(current);
// plus add a new info
} while (!atomicReference.compareAndSet(current, newArray));
}
public static MetaInfo getMeta(int key) {
return atomicReference.get().get(key);
}