我有一个程序,它有多个PublisherTask和SubscriberTask类型的对象。 给定订户可以订阅一个或多个发布者 为了描述我的问题,我将发布一些代码......
abstract class Publication {
// some published information
}
class ConcretePublicationA extends Publication {
}
class ConcretePublicationB extends Publication {
}
abstract class Subscription {
private final long id;
private final Subscriber s;
// PLUS some other members relating to the subscription
protected Subscription(long id, Subscriber s){
this.id = id;
this.s =s;
}
public Subscriber getSubscriber() {
return this.s;
}
}
class ConcreteSubscriptionA extends Subscription {
protected ConcreteSubscriptionA(long id, Subscriber s) {
super(id, s);
// TODO Auto-generated constructor stub
}
}
class ConcreteSubscriptionB extends Subscription {
protected ConcreteSubscriptionB(long id, Subscriber s) {
super(id, s);
// TODO Auto-generated constructor stub
}
}
interface Subscriber {
public void update(Publication pub);
}
interface Publisher {
public Subscription subscribe(Subscriber subscriber);
}
abstract class PublisherTask implements Runnable, Publisher {
private final ConcurrentHashMap<Long, Subscription> subscribers =
new ConcurrentHashMap<Long, Subscription>();
Long subscriptionId = 0L;
@Override
public void run() {
/*obviously this is a different variable in a real program*/
boolean some_condition = true;
while(some_condition) {
// do some work
Publication pub = /* new ConcretePublication(....) */ null;
for (Subscription s : subscribers.values()) {
s.getSubscriber().update(pub);
}
}
}
@Override
public Subscription subscribe(Subscriber subscriber) {
Subscription sub;
synchronized(subscriptionId) {
/* the lines below are in a function in the sub-class,
* but for brevity I'm showing them here
*/
sub = new ConcreteSubscriptionA(++subscriptionId, subscriber);
subscribers.put(subscriptionId, sub);
}
return sub ;
}
}
abstract class SubscriberTask implements Runnable, Subscriber {
protected ConcurrentLinkedQueue<Publication> newPublications =
new ConcurrentLinkedQueue<Publication>();
@Override
public void run() {
/*obviously this is a different variable in a real program*/
boolean some_condition = true;
while(some_condition) {
// do some work
Publication pub = newPublications.peek();
/* the lines below are in a function in the sub-class,
* but for brevity I'm showing them here
*/
{
if (pub instanceof ConcretePublicationA) {
// Do something with the published data
} else if (pub instanceof ConcretePublicationB) {
// Do something with the published data
}
}
}
}
@Override
public void update(Publication pub) {
/* My question relates to this method:
* Bascially to avoid memory issues I would like existing
* unprocessed publications **Of Tth Same Type As The New One**
* to be discarded
*/
Publication existing = null;
do {
//This won't work coz peek() only looks at the head of the queue
existing = newPublications.peek();
if ((existing != null) && (existing.getClass().equals(pub))) {
newPublications.remove(existing);
}
} while (existing != null);
newPublications.add(pub);
}
好的,现在您已经有机会仔细检查我的代码了。我想问下列问题:
在上面显示的更新方法中,是否可以查看ConcurrentLinkedQueue中的所有元素并删除给定类型的元素?
另外,如果您认为可以对课程进行改进以及如何相互交流,请随时告诉我们
感谢
答案 0 :(得分:1)
是的,可以使用迭代器查看ConcurrentLinkedQueue的所有元素。
Iterator<Publication> itr = newPublications.iterator();
while (itr.hasNext()) {
Publication existing = itr.next();
if (existing.getClass().equals(pub)) {
itr.remove();
}
}
因为ConcurrentLinkedQueue返回的迭代器保证遍历构造迭代器时存在的元素,并且可能(但不保证)反映构造之后的任何修改,您可能希望从外部锁定:
newPublications
总的来说,虽然这看起来效率不高,但应该调查完全修复重复出版物的替代解决方案。
答案 1 :(得分:0)
之前我已经解决了这个问题(或者类似的问题)。我解决它的方法是在每个新的Publication对象中有效地嵌入一个计数器(对于你正在做的事情,你需要一个每类类型的计数器)。如果消耗对象中的计数器小于当前值,则从队列中读取发布对象,然后丢弃,因为队列中有较晚的计数器。
但是,你必须小心这一点,你不会饿死你的cpu出版物,因为如果你继续快速添加新的出版物对象,你将永远不会实际处理它们中的任何一个,因为它们都将被标记为陈旧(我知道我的添加速度非常慢,比如每10分钟一次,我的任务每次运行需要几分钟,如果新的任务排在后面,那么旧的任务就没用了。)
你的解决方案看起来如果你添加A1,A2,B1,A3,A4,B2然后当你添加B2时你将不会删除B1,因为A1位于队列的头部并且不是同一类型,这不是看起来像你的评论所暗示的那样。
你可以通过输入一些帮助代码来实现我的想法:
class ValidCounter {
private Map<Class, AtomicLong> counters = new ConcurrentHashMap<Class, AtomicLong>();
public int getAtomicLongFor(Class clz) {
AtomicLong ans = counters.get(clz);
if ( ans == null ) {
counters.put(clz, new AtomicLong(0));
return 0;
}
return ans.get();
}
}
要在添加时使用,您可以在构造函数
中使用long myValidCounter = validCounterInstance.getAtomicLongFor(getClass()).incrementAndGet();
要在检查是否仍应处理时使用
long currValidCounter = validCounterInstance.getAtomicLongFor(getClass()).get();
if ( pub.getValidCounter() >= currValidCounter ) {
// still valid so process
} else {
// superceeded, so ignore
}
请记住饥饿问题 - 你可能想要添加一些东西,这些东西关心你丢弃了多少或多长时间,而且只是拿了旧东西。
我还建议您不要使用peek,只使用民意调查,或者如果您有多个消费者,您很可能会遇到线程问题(多次处理的项目)。