关于线程的中处理集合一些问题. 100分赏金来了

天体终结者 2015-01-21 10:30:27
整个生产数据的和处理数据的过程 都需要快速。希望大侠们帮忙看看,帮小弟指出有什么需要优化的地方和容易出问题的地方


//线程1---生产数据
public class DataForWlan extends Thread {
private CardReaderForWlan rr;
public static Set<String> carIdAndTimeSet = Collections.synchronizedSet( new HashSet<String>());

public Set<String> getCarIdAndTimeSet() {
return carIdAndTimeSet;
}

public void setCarIdAndTimeSet(Set<String> carIdAndTimeSet) {
this.carIdAndTimeSet = carIdAndTimeSet;
}

// 初始化线程类
private void init() {
try {
rr = new CardReaderForWlan(); //创建无线读卡连接
} catch (ReaderException e) {
e.printStackTrace();
return;
}
if (rr == null) {
return;
}
}

public synchronized void run() {
init();
try {
while (true) {
TagReadData[] trd = rr.MultiReadCard(); //不断的读卡 但不一定每时每刻都有数据产生
if (trd.length > 0) {
readCar(trd);
}
//this.sleep(5);
}
} catch (Exception e) {
this.stop();
e.printStackTrace();
}
}

/**
* 处理需要的数据
*/
public void readCar(TagReadData[] trd) {
try {
int trdLength = trd.length;
if (trdLength <= 0) {
return;
}
for (int i = 0; i < trdLength; i++) {
String cardID = trd[i].EPCHexstr(); //卡ID
String carIdAndTime = cardID +","+ System.currentTimeMillis()/1000;//用于线程2处理数据用
carIdAndTimeSet.add(carIdAndTime);//短时间内会读一张卡几次,但只需要一结果即可
}
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 清空数据
*/
public void clearcarIdAndTimeSet(){
carIdAndTimeSet.clear();
}


}




线程2

public class MainJFrame extends javax.swing.JFrame implements ActionListener , Runnable{
public Set<String> carIAndTime =null;//读到的卡号存放
public Set<String> cardIdlist = new HashSet<String>();//显示面板存放卡号

public DataForWlan dfw= new DataForWlan ();//无线读卡器线程

public void run() {
while (true) {
try {
carIAndTime = new HashSet<String>();
carIAndTime.addAll(dfw.getCarIdAndTimeSet());//将线程1中的值赋值给carIAndTime
dfw.clearcarIdAndTimeSet();//清空数据
if(carIAndTime.size()!=0){
Iterator<String> iterator = carIAndTime.iterator();
while(iterator.hasNext()){
String cardTime = iterator.next();
String [] strs = cardTime.split("[,]");
String cardID = strs[0];//卡ID
user = listAllUsers.get(strs[0]);//根据卡ID得到签到人员
if(user != null){
long time = Long.valueOf(strs[1]);
Iterator<String> keys = map.keySet().iterator();
if(keys.hasNext()){//以下是做业务处理可以忽略
boolean re = isExist(map, cardID);
if(re){//存在
long aftertime = map.get(cardID);//前一个时间
if (time - aftertime > 30) {
map.put(strs[0], Long.valueOf(strs[1]));
cardIdlist.add(strs[0]);
}
}else{
map.put(strs[0], Long.valueOf(strs[1]));
cardIdlist.add(strs[0]);
}
}else{
map.put(strs[0],Long.valueOf(strs[1]));
cardIdlist.add(strs[0]);
}
setCarIdOfTime(cardIdlist);//将得到数据,进行业务处理
cardIdlist.clear();
iterator.remove();//后来加的
}
}
}
Thread.currentThread().sleep(600);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public boolean isExist(Map<String, Long> map, String abc){
boolean isexit = false;
Iterator<String> keys = map.keySet().iterator();
if(keys.hasNext()){
while (keys.hasNext()) {
String key = (String)keys.next();
if (abc.equals(key)) {//判断此卡号在map中不存在
return true;
}
}
}
return isexit;
}
}



运行几个小时后报错如下。有的时候几十分钟也会报这个错误
这个错误也是我最常看到的,经常出现。

Exception in thread "Thread-4" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(Unknown Source)
at java.util.HashMap$KeyIterator.next(Unknown Source)
at java.util.AbstractCollection.addAll(Unknown Source)
at indexframes.MainJFrame.run(MainJFrame.java:380)
at java.lang.Thread.run(Unknown Source)

//380行就是线程2中的
carIAndTime.addAll(dfw.getCarIdAndTimeSet());


但是在线程2中添加下面代码后已经跑了12个小时。还在测试中

iterator.remove();//后来加的
...全文
341 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
淡定的峰哥 2015-01-26
  • 打赏
  • 举报
回复
java.util.ConcurrentModificationException 这个异常多发生在对集合进行迭代的时候 意思是说:迭代器在进行迭代的时候不允许外面对它进行修改,说的很拗口,举个例子就是

List<String> list = new ArrayList<String>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        Iterator<String> iterator = list.iterator();//迭代的时候
        while(iterator.hasNext()){
            String s = iterator.next();
            list.remove(s);//外部修改是不行的
            //iterator.remove();//内部修改时可以的
        }
        System.out.println(list.size());

那么LZ报错的那个地方 carIAndTime.addAll(dfw.getCarIdAndTimeSet());/ 看看AbstractCollection的源码就知道了

public boolean addAll(Collection<? extends E> c) {
        boolean modified = false;
        Iterator<? extends E> e = c.iterator();
        while (e.hasNext()) {
            if (add(e.next()))
                modified = true;
        }
        return modified;
    }
addAll方法也用到了迭代器,这个方法的入参来自你第一个线程,在迭代的时候即addAll的那一刻,被线程1给改了,就会抛出 java.util.ConcurrentModificationException 而且你这是生产者消费者模式,不能用set,要用queue,即是是多次读,也要用queue包装一下
天体终结者 2015-01-24
  • 打赏
  • 举报
回复
引用 10 楼 windsunmoon 的回复:
如果你只有这两个线程的话,应该没问题。 不过看你线程2中定义的变量是 public ,是不是有其他线程也访问了。
没有其他线程访问线程2中的数据
天体终结者 2015-01-24
  • 打赏
  • 举报
回复
继续帮忙啊 谢谢楼上几位
wapigzhu 2015-01-23
  • 打赏
  • 举报
回复
public boolean isExist(Map<String, Long> map, String abc){ return map.get(abc) != null; }
wuyoutianxialove 2015-01-23
  • 打赏
  • 举报
回复
引用 11 楼 windsunmoon 的回复:
看你 贴出来的异常信息是 hashMap的 迭代器失效错误,但是你说380行是
carIAndTime.addAll(new HashSet<String>(dfw.getCarIdAndTimeSet()));
却又是 hashset,怪哉
HashSet 内部就是一个HashMap
windsunmoon 2015-01-23
  • 打赏
  • 举报
回复
看你 贴出来的异常信息是 hashMap的 迭代器失效错误,但是你说380行是
carIAndTime.addAll(new HashSet<String>(dfw.getCarIdAndTimeSet()));
却又是 hashset,怪哉
windsunmoon 2015-01-23
  • 打赏
  • 举报
回复
如果你只有这两个线程的话,应该没问题。 不过看你线程2中定义的变量是 public ,是不是有其他线程也访问了。
whos2002110 2015-01-22
  • 打赏
  • 举报
回复
引用 7 楼 hzxljin 的回复:
[quote=引用 1 楼 whos2002110 的回复:] 报错的原因是addAll方法中在迭代carIdAndTimeSet, 而线程1中又往carIdAndTimeSet里加数据. 这样改下:

carIAndTime.addAll(new HashSet<String>(dfw.getCarIdAndTimeSet()));
不行跑了8个小时也挂了[/quote] 不好意思, 我的方法其实跟你之前没有本质区别,还是一样的错误。 但是错误如我所说,不能再迭代的过程中往里放数据。 你可以使用ConcurrentHashMap, 用这个Map实现Set的功能。 ConcurrentHashMap 可以边迭代边加数据。 不然的话只能加锁了,手动对Set中数据的进出进行同步。
天体终结者 2015-01-22
  • 打赏
  • 举报
回复
引用 1 楼 whos2002110 的回复:
报错的原因是addAll方法中在迭代carIdAndTimeSet, 而线程1中又往carIdAndTimeSet里加数据. 这样改下:

carIAndTime.addAll(new HashSet<String>(dfw.getCarIdAndTimeSet()));
不行跑了8个小时也挂了
天体终结者 2015-01-21
  • 打赏
  • 举报
回复
引用 2 楼 lwb314 的回复:
没看到你map的定义,不过看提示你用的是HashMap,HashMap是非线程安全的,多线程最好用HashTable,你可以换一下再试试看报错不
private Map<String, Long> map = new ConcurrentHashMap<String,Long>();
天体终结者 2015-01-21
  • 打赏
  • 举报
回复
我晕,我没法回复上面的楼层 还有编辑自己的帖子也不行

private Map<String, Long> map = new ConcurrentHashMap<String,Long>();
  • 打赏
  • 举报
回复
没看到你map的定义,不过看提示你用的是HashMap,HashMap是非线程安全的,多线程最好用HashTable,你可以换一下再试试看报错不
whos2002110 2015-01-21
  • 打赏
  • 举报
回复
报错的原因是addAll方法中在迭代carIdAndTimeSet, 而线程1中又往carIdAndTimeSet里加数据. 这样改下:

carIAndTime.addAll(new HashSet<String>(dfw.getCarIdAndTimeSet()));
天体终结者 2015-01-21
  • 打赏
  • 举报
回复
引用 5 楼 lwb314 的回复:
[quote=引用 4 楼 hzxljin 的回复:] [quote=引用 2 楼 lwb314 的回复:] 没看到你map的定义,不过看提示你用的是HashMap,HashMap是非线程安全的,多线程最好用HashTable,你可以换一下再试试看报错不
private Map<String, Long> map = new ConcurrentHashMap<String,Long>();[/quote]你没试试1楼的吗?[/quote] 暂时没试。系统还在正常的跑着。稍后再试试
  • 打赏
  • 举报
回复
引用 4 楼 hzxljin 的回复:
[quote=引用 2 楼 lwb314 的回复:] 没看到你map的定义,不过看提示你用的是HashMap,HashMap是非线程安全的,多线程最好用HashTable,你可以换一下再试试看报错不
private Map<String, Long> map = new ConcurrentHashMap<String,Long>();[/quote]你没试试1楼的吗?

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧