如果有更重要的消息进入,则添加到消息队列

时间:2016-09-20 06:35:33

标签: java concurrency

我们需要先发送优先级最高的邮件,以便我们使用PriorityQueue作为目的。

PriorityQueue<MessageData> queue = new PriorityQueue<MessageData>();

但是,我们也希望我们的队列行为也像排序集一样。因此,我们调整PriorityQueue以忽略重复现有成员的插入。

import java.util.Comparator;
import java.util.PriorityQueue;

public class PrioritySet<E> extends PriorityQueue<E> {

    private static final long serialVersionUID = 34658778L;

    public PrioritySet() {
        super();
    }

    public PrioritySet(int initialCapacity, Comparator<? super E> comparator) {
        super(initialCapacity, comparator);
    }

    @Override
    public boolean offer(E e) {
        boolean isAdded = false;
        if(!super.contains(e)) {
            isAdded = super.offer(e);
        }
        return isAdded;
    }
}

现在我们的app特定的数据结构实现。

import java.util.Comparator;

public class MessagePrioritySet extends PrioritySet<MessageData> {

    private static final long serialVersionUID = 34658779L;

    private int minPriorityNumber;

    public MessagePrioritySet() {
        super();
    }

    public MessagePrioritySet(int initialCapacity, Comparator<MessageData> comparator) {
        super(initialCapacity, comparator);
    }

    public synchronized int getMinPriorityNumber() {
        return minPriorityNumber;
    }

    public synchronized void setMinPriorityNumber(int minPriorityNumber) {
        this.minPriorityNumber = minPriorityNumber;
    }

    @Override
    public synchronized boolean offer(MessageData notification) {
        boolean isAdded = super.offer(notification);
        if (notification.getPriority() < minPriorityNumber)
            minPriorityNumber = notification.getPriority();
        return isAdded;
    }

    public synchronized void reportSent(MessageData notification) {
        MessageData nextMessageData = peek();
        if (nextMessageData == null)
            minPriorityNumber = 0;
        else if (nextMessageData.getPriority() > notification.getPriority())
            minPriorityNumber = nextMessageData.getPriority();
    }
}

在这里,我们希望数据结构知道消息的最小优先级值,因此我们为此声明了一个实例变量。检查传入消息的优先级,如果该优先级低于存储值,则更新存储的值。需要使用该类来报告任何已发送的消息。如果数据结构中没有其他成员的优先级低于要删除的优先级,则下一个元素的优先级将成为存储的优先级。

两个线程共享已实现的队列。一个线程从数据库中提取数据并将其插入队列。另一个读取队列并发送具有最低优先级编号的最高优先级消息。因为队列将最小优先级值设置为0,并且从数据库获取数据的线程读取优先级值小于或等于存储在队列中的最小值的行(如果存储的最小值不为零),我们可以非常确定当发送队列中的当前消息时,只有比队列中已有的消息更重要的新消息才会被添加到队列中。

我们认为线程中while循环中的操作应该是原子的,并且会感谢任何能告诉我们如何使它们成为原子的人。

private void startMptSender() {
    sleepInterval = 1000;
    final MessagePrioritySet messagePrioritySet = new MessagePrioritySet();

    Runnable mptReader = new Runnable() {

        @Override
        public void run() {
            while (true) {
                List<MessageData> messageDataList;

                if (messagePrioritySet.getMinPriorityNumber() == 0)
                    messageDataList = messageDao.readSMSMpt();
                else
                    messageDataList = messageDao.readSMSMpt(messagePrioritySet.getMinPriorityNumber());

                for (MessageData messageData : messageDataList) {
                    messagePrioritySet.offer(messageData);
                }
                try {
                    Thread.sleep(sleepInterval);
                } catch (InterruptedException ie) {

                }
            }
        }
    };

    executor.execute(mptReader);

    Runnable mptPusher = new Runnable() {

        @Override
        public void run() {
            while (status) {
                if (messagePrioritySet.size() > 0) {

                    while (messagePrioritySet.size() != 0) {
                        MessageData noti = messagePrioritySet.remove();
                        mptSender.sendSms(noti);
                        messageDao.markNotificationAsRead(noti.getSyskey());
                        messagePrioritySet.reportSent(noti);
                        try {
                            Thread.sleep(sleepInterval);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                } else {
                    try {
                        Thread.sleep(sleepInterval);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    };

    executor.execute(mptPusher);
}

}

1 个答案:

答案 0 :(得分:1)

我假设您对原子的意思转换为:您希望每个帖子在一次迭代中完全 被另一个线程打断了。

换句话说:你有(可能是多个)操作;当线程A正在进行操作时,线程B不应该做任何事情 - 因为你想确保B只看到&#34;完整的设置&#34; A的更新。

当然,例如,当该操作只是写入一个int时,您可能正在使用AtomicInteger。但是当你谈论几个操作时......你还需要别的东西。

A&#34;蛮力&#34;解决方案是添加某种锁定。含义:你的线程共享一些LOCK对象;每当一个线程进入&#34;关键部分时#34; ......它需要首先获得该LOCK(当然之后直接释放)。但这需要非常仔细的设计;因为想要确保线程A不是“挨饿”#34; B持有这个锁太久了。

再次查看你的代码,更密切......也许你可以尝试让你的minPriority成为AtomicInteger;问题是这将如何与正在运作&#34; size&#34;你的队列。