我做了两个线程,一个是获取数据,另一个是保存数据。 我的问题是,在存储从Thread1读取的数据的过程中没有处理该问题。
我想提取1,000,000个元素并将其创建为文件。元素大小很大,所以我将元素大小除以100,000。然后,循环将运行10次。一个线程从另一台服务器读取100,000个数据。另一个线程从第一个线程获取数据并将其写入文件。
我的原始情况如下:
第一个线程读取总键,值大小。 这将是100,000〜1,000,000。我假设我将处理1,000,000数据。然后Count设置1,000,000。第一个线程除以100,000,然后从服务器读取100,000。然后,第一个线程调用setData(Key,Value map)。 它将循环十次。
第二个线程将循环10次。首先,通过调用getMap()方法获取数据。并调用writeSeq(hashmap)方法。它将数据写入写程序流。它还没有冲洗。这里有问题。它通过调用getMap()成功获取数据大小。但是,writeSeq方法无法处理所有大小的值。当我得到100,000的大小时,它作为随机处理。分别是100、1500、0、8203 ...
第一个线程在下面:
public void run() {
getValueCount(); //initialize value.
while (this.jobFlag) {
getSortedMap(this.count); //count starts the number of all elements size.
//For example, Total size is 1,000,000. Then count will sets a 1,000,000 and it is decreased as 100,000.
// Also setMap() is called in this method.
if (!jobFlag) //If all processing is done, jobFlag is set as false.
break;
}
resetValue();
}
第二个线程在下面:
public void run() {
setWriter(); //Writer Stream creates;
double count = 10; //the number of loop.
ConcurrentHashMap<String, String> hash = new ConcurrentHashMap<String,String>();
for (int i = 0; i <= count - 1; i++) {
hash = share.getMap();
writeSeq(hash);
}
closeWriter(); //close Writer stream
}
这是共享源:
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
public class ShareData {
ConcurrentHashMap<String, String> map;
public synchronized ConcurrentHashMap<String, String> getMap(){
if (this.map == null) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
ConcurrentHashMap<String, String> hashmap = map;
this.map = null;
return hashmap;
}
public synchronized void setMap(ConcurrentHashMap<String, String> KV) {
if (this.map != null) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.map = KV;
notify();
}
}
在那之后,第二个保存数据的线程被盯着。 KV的大小很好,但是在进行foreach时不会处理所有值。此外,每次创建文件时,大小都是不同的。是同步的问题吗?
public synchronized void writeSeq(ConcurrentHashMap<String, String> KV) {
AtomicInteger a = new AtomicInteger(0);
System.out.println(KV.size()); //ex) 65300
redisKV.entrySet().parallelStream().forEach(
entry -> {
try {
a.incrementAndGet();
writer.append(new Text(entry.getKey()), new Text(entry.getValue()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
});
System.out.println(a.get()); //ex) 1300
i = 0;
notify();
}
答案 0 :(得分:1)
i++;
不是thread-safe。您得到的数量将少于更新的数量。改用AtomicInteger
及其incrementAndGet()
方法。
答案 1 :(得分:1)
更好的方法是使用BlockingQueue,一个线程放入队列,另一个线程从队列中取出。
答案 2 :(得分:1)
KV的大小合适,但是在处理foreach时不会处理所有值。另外,每次创建文件时,大小都不同。是同步的问题吗?
不清楚。我可以看到一个小问题,但这不太可能导致您描述的问题。
if (map == null) wait();
代码应为while
循环。
if (map != null) wait();
代码应为while
循环。
问题在于,如果一个线程收到虚假通知,则它可能会以错误状态继续map
。您需要重试测试。 (如果您阅读Object
的Javadoc,则会看到一个示例,该示例正确实现了条件变量。)
除此之外,您的问题的根本原因似乎不在您显示给我们的代码中。
但是,如果我要猜测,我的猜测是一个线程正在添加或删除ConcurrentHashMap
中的条目,而第二个线程正在处理它 1 。您向我们展示的getMap
/ setMap
方法必须被适当地使用(即在适当的位置使用适当的参数调用),以避免两个线程相互干扰。您尚未向我们显示该代码。
因此,如果我的猜测正确,那么您的问题是逻辑错误而不是低级同步问题。但是,如果您需要更好的答案,则需要编写和发布适当的MCVE。
1-ConcurrentHashMap的迭代器弱一致。这意味着,如果您在迭代时更新地图,则可能会错过迭代中的条目,或者可能多次看到它们。