📄 consumer.java
字号:
/**
*
*/
package problem8_3;
import java.util.*;
/**
* @author Administrator
*
*/
//实现Runnable接口,而不是继承Thread类,主要是为了方便共享数据
public class Consumer implements Runnable{
// 生产者的pStrList与消费者的cStrList是同步的,因为等号赋值相当于引用
StrArray cStrList;
// outputNum定义消费者已经消费多少数据
int outputNum;
// consumeSize定义消费者总共可以消费多少数据
int consumeSize;
public Consumer(StrArray aStrArray,int i) {
cStrList=aStrArray;
consumeSize=i;
outputNum=0;
}
public Consumer() {
}
public void run() /*throws InterruptedException*/{
// 如果Producer没有生产数据或数据已被消费完,则消费者等待
try{if(cStrList.stringArray.size()==0) Thread.sleep(10);
} catch(InterruptedException e){
System.out.println("Consumer can not sleep");
}
// 同步是为了防止Str.remove()时抛出异常,因为可能同时有两个Consumer线程在修改Str,而这时不允许的(使用Iterator类的remove()只能避免在单线程中抛出异常),详情见下面的注释
// 注意synchronized括号内的参数必须是本类的数据成员
synchronized (cStrList) {
// 注意,cStrList.stringArray.size()会随着str.remove()而改变
if (cStrList.stringArray.size() != 0) {
Iterator Str = cStrList.stringArray.iterator();
while (Str.hasNext()) {
System.out.println(Thread.currentThread().getName()
+ " consume " + Str.next());
Str.remove();
outputNum++;
if (outputNum == consumeSize) {
System.out.println(Thread.currentThread().getName()
+ "消费" + consumeSize + "个数据完毕,结束消费");
// 退出while循环,从而退出这个线程
break;
}
}
}
}
// 为了方便调试时设置断点用
System.out.println(Thread.currentThread().getName()+" end");
}
}
//在Java里,当使用一个迭代器去迭代一个对象(Collection或是Map等等)时,如果在迭代过程中,对象被修改了,那么就会抛出ConcurrentModificationException异常。那么,我们如何避免这种情况,去安全的使用迭代器呢?
//
//当我们需要在迭代的时候修改这个对象时,我们必须使用迭代器本身的API去修改这个对象,而不能用对象自己的API去修改。比如说,我们想删除对象里满足某种条件的元素时,我们可以用:
//
//Iterator it = map.keySet().iterator();
//while(it.hasNext()) {
//it.next();
//if(somecondition)it.remove();
//}
//
//使用Iterator本身的remove方法时,它不仅会删除对象里的元素,同时也会更新迭代器本身。但是如果使用对象本身的API去修改的话:
//
//Iterator it = map.keySet().iterator();
//while(it.hasNext()) {
//if(somecondition)map.remove(it.next());
//}
//
//由于对象本身的API只会修改对象自己,而不回去更新迭代器,所以迭代器依然会迭代这个被删除的元素,那么就会抛出ConcurrentModificationException异常了。
//
//以上方法可以保证在同一个线程里迭代器的安全使用,但是,在多线程的环境下,即使你使用迭代器的API去修改对象,或者你根本就没有去修改对象,你也不能保证在你迭代的过程中,其他的线程没有去修改这个对象。那么唯一的方法,就是当一个线程在迭代的过程中,把这个对象锁住,使其它的线程无法对这个对象就行修改。这个时候我们就需要用到Java的同步机制了。我们应该:
//
//
//synchronized(map) {
//Iterator it = map.keySet().iterator();
//while(it.hasNext()) {
//……
//}
//}
//
//由于synchronized关键字是完全锁住一个对象,不论是读还是写。如果想提高性能,在迭代过程中允许读的话,那么就需要用到concurrent.jar包了,创建一个写锁来替换synchronized。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -