我有几个使用ArrayBlockingQueue的工作者。
每个worker从队列中获取一个对象,处理它,结果可以得到几个对象,这些对象将被放入队列中进行进一步处理。所以,工人=生产者+消费者。
工人:
public class Worker implements Runnable
{
private BlockingQueue<String> processQueue = null;
public Worker(BlockingQueue<String> processQueue)
{
this.processQueue = processQueue;
}
public void run()
{
try
{
do
{
String item = this.processQueue.take();
ArrayList<String> resultItems = this.processItem(item);
for(String resultItem : resultItems)
{
this.processQueue.put(resultItem);
}
}
while(true);
}
catch(Exception)
{
...
}
}
private ArrayList<String> processItem(String item) throws Exception
{
...
}
}
主要
public class Test
{
public static void main(String[] args) throws Exception
{
new Test().run();
}
private void run() throws Exception
{
BlockingQueue<String> processQueue = new ArrayBlockingQueue<>(10000);
processQueue.put("lalala");
Executor service = Executors.newFixedThreadPool(100);
for(int i=0; i<100; ++i)
{
service.execute(new Worker(processQueue));
}
}
}
当没有工作时,什么是阻止工人的最好方法?
首先,我想到的是定期检查队列中有多少项目以及当前正在处理多少项目。如果两者都等于零,那么在ExecutorService上执行类似“shutdownNow()”的操作。但我不确定这是最好的方式。
答案 0 :(得分:2)
如果没有其他工作要做,请在队列中输入一条消息,然后让工作人员自行关闭。这是防止数据损坏的好方法。
如果您需要通知另一个线程所有工作人员已经回家,您可以使用CountDownLatch
来执行此操作。
答案 1 :(得分:1)
听起来你有自己的解决方案 - 使用一个单独的正在进行的队列,其大小将是当前正在处理的项目数。如果您使用访问任一队列的约定在synchronized(theArrayBlockingQueue)
块中,那么一切都应该很好。特别是,当将项目移动到处理状态时,将其从ArrayBlockingQueue中移除并将其添加到相同同步块中的processingQueue。
答案 2 :(得分:0)
我稍微修改了你的代码,不确定这是否是你所期望的,但至少它终止了!如果您使用shutdownNow
而不是shutdown
,您的工作人员将被中断,除非您将其重新投入工作,否则将退出而不保证队列为空。
public class Test {
public static void main(String[] args) throws Exception {
new Test().run();
}
private void run() throws Exception {
BlockingQueue<String> processQueue = new ArrayBlockingQueue<>(10000);
processQueue.put("lalalalalalalalalalalalala"); //a little longer to make sure there is enough to process
ExecutorService service = Executors.newFixedThreadPool(100);
for (int i = 0; i < 100; ++i) {
service.execute(new Worker(processQueue));
}
service.shutdown(); //orderly shutdown = lets the tasks terminate what they are doing
service.awaitTermination(1, TimeUnit.SECONDS); //blocks until all tasks have finished or throws TimeOutException if timeout is reached
}
public static class Worker implements Runnable {
private BlockingQueue<String> processQueue = null;
private int count = 0;
public Worker(BlockingQueue<String> processQueue) {
this.processQueue = processQueue;
}
@Override
public void run() {
try {
do {
//tries to get something from the queue for 100ms and returns null if it could not get anything
String item = this.processQueue.poll(100, TimeUnit.MILLISECONDS);
if (item == null) break; //Ends the job because the queue was empty
count++;
List<String> resultItems = this.processItem(item);
for (String resultItem : resultItems) {
this.processQueue.put(resultItem);
}
} while (true);
} catch (InterruptedException e) {
System.out.println("Interrupted");
Thread.currentThread().interrupt();
}
if (count != 0) System.out.println(Thread.currentThread() + ": processed " + count + " entries");
}
private List<String> processItem(String item) { //let's put the string back less final character
if (item.isEmpty()) {
return Collections.<String> emptyList();
} else {
return Arrays.asList(item.substring(0, item.length() - 1));
}
}
}
}