我试图根据在实例化时给予它们的权重将对象分成五个不同的组。
现在,我想按权重将这些对象分为五组。为此,必须将每个人与另一个人进行比较。
现在我遇到的问题是这些对象被添加到单独的工作线程上的组中。每个被发送到同步排序功能,该功能在对象完成下载图片之后与当前在三个组中的所有成员进行比较。
这些组已被设置为两个不同的地图。第一个是Hashtable,它崩溃了抛出未知ConcurrencyIssue的程序。当我使用ConcurrentHashMap时,数据是错误的,因为它不会在将下一个对象与ConcurrentHashmap进行比较之前及时删除该条目。因此,这会导致逻辑错误并产生仅在一半时间内正确排序的组。
我需要哈希映射在下一次排序之前立即从地图中删除条目...我认为同步该功能会这样做,但它似乎仍然不起作用。
是否有更好的方法可以将工作线程添加到数据结构中的对象相互排序?谢谢!我在这一点上有点失落。
private synchronized void sortingHat(Moment moment) {
try {
ConcurrentHashMap[] helperList = {postedOverlays, chanl_2, chanl_3, chanl_4, chanl_5};
Moment moment1 = moment;
//Iterate over all channels going from highest channel to lowest
for (int i = channelCount - 1; i > 0; i--) {
ConcurrentHashMap<String, Moment> table = helperList[i];
Set<String> keys = table.keySet();
boolean mOverlap = false;
double width = getWidthbyChannel(i);
//If there is no objects in table, don't bother trying to compare...
if (!table.isEmpty()) {
//Iterate over all objects currently in the hashmap
for (String objId : keys) {
Moment moment2 = table.get(objId);
//x-Overlap
if ((moment2.x + width >= moment1.x - width) ||
(moment2.x - width <= moment1.x + width)) {
//y-Overlap
if ((moment2.y + width >= moment1.y - width) ||
(moment2.y - width <= moment1.y + width)) {
//If there is overlap, only replace the moment with the greater weight.
if (moment1.weight >= moment2.weight) {
mOverlap = true;
table.remove(objId);
table.put(moment1.id, moment1);
}
}
}
}
}
//If there is no overlap, add to channel anyway
if (!mOverlap) {
table.put(moment1.id, moment1);
}
}
} catch (Exception e) {
Log.d("SortingHat", e.toString());
}
}
table.remove(objId)
是问题发生的地方。时刻A被发送到排序功能,没有问题。添加了时刻B,它重叠,它与时刻A进行比较。如果时刻B的重量小于时刻A,则一切都很好。如果时刻B被加权更多并且A必须被移除,那么当时刻C被排序时,时刻A仍将与时刻B一起在哈希映射中。所以这似乎是逻辑错误所在的位置。
您的同步问题。
您使用的同步将使用“this”锁同步。你可以想象它是这样的:
public synchronized void foo() { ... }
是相同的
public void foo() {
synchronized(this) {
....
}
}
这意味着,在进入之前,当前线程将尝试获取“此对象”作为锁。现在,如果你有一个工作线程,它也有一个同步方法(用于向表中添加东西),它们不会完全相互排斥。你想要的是,一个Thread必须完成他的工作,然后才能开始工作。
第一个是Hashtable,它崩溃了抛出未知ConcurrencyIssue的程序。
这个问题可以解决,因为它可能会发生,2个线程同时调用某个东西。为了说明,想象一个线程调用put(key,value)和另一个调用remove(key)的线程。如果这些调用同时执行(如不同的内核),那么生成的HashTable会是什么?因为没有人可以肯定地说,所以会抛出ConcurrentModificationException。注意:这是一个简单的简单解释!
当我使用ConcurrentHashMap时,数据是错误的,因为它不会在将下一个对象与ConcurrentHashmap进行比较之前及时删除该条目
ConcurrentHashMap是一个实用程序,为了避免所述并发问题,它不是神奇的,多功能的,独角兽狩猎,黄油刀。它会对mehtod调用进行同步,这导致只有一个线程可以在HashMap上添加或删除或执行任何其他工作。它没有与某种类型的Lock相同的功能,这将导致对地图的访问被分配到Thread上。
可能有一个想要调用add的线程和一个想要调用remove的线程。 ConcurrentHashMap仅限制这些调用,它们不能同时发生。哪个先来?你有权力(在这种情况下)。你想要的是,一个线程必须完成他的工作,然后才能完成它的工作。
你真正需要的是你自己。 java.util.concurrent package带来了一整套你可以使用的类。例如:
你可以为每张地图使用lock。有了它,每个线程(排序/删除/添加或其他)可以首先获取所述地图的锁定,然后在该地图上工作,如下所示:
public Worker implements Runnable {
private int idOfMap = ...;
@Override
public void run() {
Lock lock = getLock(idOfMap);
try {
lock.lock();
// The work goes here
//...
} finally {
lock.unlock();
}
}
}
行lock.lock()将确保,在方法调用返回之后,没有其他Thread正在Map上工作并修改它,因此这个Thread将通过Map进行mutial访问。在你完成删除正确的元素之前,没有人排序。
当然,你会以某种方式持有所述锁,就像在数据对象中一样。话虽如此,您还可以利用信号量,在每个线程中同步(映射)或以Runnables的形式在Map上制定您的工作,并将它们传递给另一个调用他逐个接收的所有Runnables的线程。可能性几乎无穷无尽。我个人会建议从锁定开始。