Java 多线程访问地图上的精确数据
我正试图根据实例化时给定的权重将对象分为五个独立的组 现在,我想根据它们的权重将这些对象分为五组。为了做到这一点,必须对每一个进行比较 现在我遇到的问题是,这些对象被添加到单独工作线程上的组中。在一个对象完成图片下载后,每个对象都会被发送到同步排序功能,该功能会与当前三个组中的所有成员进行比较 这些组被设置为两张不同的地图。第一个是哈希表,它使程序崩溃,抛出未知并发。当我使用ConcurrentHashMap时,数据是错误的,因为它没有在下一个对象与ConcurrentHashMap进行比较之前及时删除条目。因此,这会导致逻辑错误,并且只会在一半的时间内产生正确排序的组 我需要hashmap在下一次排序之前立即从映射中删除条目。。。我以为同步函数可以做到这一点,但它似乎仍然不起作用 有没有更好的方法对工作线程添加到数据结构中的对象进行相互排序?谢谢我有点迷路了Java 多线程访问地图上的精确数据,java,data-structures,java-7,concurrenthashmap,Java,Data Structures,Java 7,Concurrenthashmap,我正试图根据实例化时给定的权重将对象分为五个独立的组 现在,我想根据它们的权重将这些对象分为五组。为了做到这一点,必须对每一个进行比较 现在我遇到的问题是,这些对象被添加到单独工作线程上的组中。在一个对象完成图片下载后,每个对象都会被发送到同步排序功能,该功能会与当前三个组中的所有成员进行比较 这些组被设置为两张不同的地图。第一个是哈希表,它使程序崩溃,抛出未知并发。当我使用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());
}
}
private synchronized void sortingHat(瞬间){
试一试{
ConcurrentHashMap[]helperList={postedOverlays,chanl_2,chanl_3,chanl_4,chanl_5};
力矩1=力矩;
//迭代从最高通道到最低通道的所有通道
对于(int i=channelCount-1;i>0;i--){
ConcurrentHashMap表=helperList[i];
设置键=table.keySet();
布尔mOverlap=false;
双宽度=getWidthbyChannel(i);
//若表中并没有对象,就不要费心去比较。。。
如果(!table.isEmpty()){
//迭代当前hashmap中的所有对象
for(字符串对象:键){
力矩2=表get(objId);
//x重叠
如果((动量2.x+宽度>=动量1.x-宽度)||
(动量2.x-宽度=动量1.y-宽度)||
(动量2.y-宽度=动量2.重量){
mOverlap=true;
表.删除(objId);
表1.put(动量1.id,动量1);
}
}
}
}
}
//如果没有重叠,仍要添加到通道
如果(!mOverlap){
表1.put(动量1.id,动量1);
}
}
}捕获(例外e){
Log.d(“SortingHat”,例如toString());
}
}
表。删除(objId)
是出现问题的地方。矩A被发送到排序函数,并且没有问题。矩B被添加,它重叠,它与矩A比较。如果矩B的权重小于矩A,则一切正常。如果矩B的权重更大,并且必须删除矩A,那么当矩C被排序时,矩A仍将在哈希映射中以及力矩B。这似乎就是逻辑错误所在。您的同步出现问题
您使用的同步将使用“this”锁进行同步。您可以想象它是这样的:
public synchronized void foo() { ... }
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();
}
}
}
与
public void foo() {
synchronized(this) {
....
}
}
这意味着,在进入之前,当前线程将尝试获取“This object”作为锁。现在,如果您有一个工作线程,它也有一个同步方法(用于向表中添加内容),它们不会完全相互排斥。您想要的是,一个线程必须完成其工作,然后下一个线程才能开始其工作
第一个是哈希表,它使程序崩溃,抛出未知并发
这个问题之所以出现,是因为可能会有两个线程同时调用某个对象。举例来说,假设一个线程对其调用put(key,value),另一个线程调用remove(key)。如果这些调用同时执行(比如由不同的核执行)结果的哈希表是什么?因为没有人可以肯定地说,会抛出一个。注意:这是一个非常简单的解释
当我使用ConcurrentHashMap时,数据是错误的,因为它没有在下一个对象与ConcurrentHashMap进行比较之前及时删除条目
ConcurrentHashMap是一个实用程序,为了避免上述并发问题,它不是神奇的、多功能的、猎取独角兽的黄油刀。它同步Method调用,结果是,只有一个线程可以在HashMap上添加、删除或做任何其他工作。它的功能与锁不同某种类型的,这将导致通过映射的访问被分配到线程上
可能有一个线程想要调用add,另一个线程想要调用remove。ConcurrentHashMap只限制了这些调用,它们不能同时发生。哪一个是第一个?您可以控制它(在这个场景中).你想要的是,一个线程必须完成他的工作,然后下一个线程才能完成它的工作
你真正需要的是你自己。它提供了一整套你可以使用的课程。例如:
您可以为每个映射使用一个。这样,每个线程(排序/删除/添加或其他)都可以首先获取所述映射的锁,然后处理该映射,如下所示:
public synchronized void foo() { ... }
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();
}
}
}
line lock.lock()将确保在方法调用返回后,没有其他线程正在处理映射并对其进行修改,因此该线程将具有对映射的多重访问权。在完成删除正确元素之前,没有任何排序
当然,你可能不得不持有这把锁