我想以多线程方式阅读10封邮件帐户的未读邮件。
但是如果线程池大小为5,那么将从线程池中使用5个线程。每个线程将读取一个邮件帐户。因此,一旦Thread_1读取了第一个邮箱,它应该读取mailbox_6。然后线程2将读取mailbox_7。
当所有邮件帐户都被阅读一次后,该周期将从第一个邮件帐户开始。
我们怎样才能在java中做到这一点?
答案 0 :(得分:4)
这应该很简单。您创建一个包含5个线程的固定线程池,然后将10个作业提交到池中 - 每个用户电子邮件帐户1个:
// create a thread pool with 5 workers
ExecutorService threadPool = Executors.newFixedThreadPool(5);
// submit all 10 user email accounts to the pool to be processed in turn
for (UserEmail userEmail : userEmailsToProcess) {
threadPool.submit(new EmailProcessor(userEmail));
}
// once we have submitted all jobs to the thread pool, it should be shutdown
threadPool.shutdown();
...
// here's our runnable class which does the actual work
public class EmailProcessor implements Runnable {
private UserEmail userEmail;
public MyJobProcessor(UserEmail userEmail) {
this.userEmail = userEmail;
}
public void run() {
// read the user email
...
}
}
UserEmail
类可以将电子邮件的文件名保存为“已读”或可能是帐户名称或其他内容。由您来决定如何表示要阅读的邮件帐户和邮件。
[[来自评论:]]
我有10个邮箱,比如.. mailbox1 ... mailbox10,现在我有5个来自线程池的线程,所以thread1将获取任何邮箱,所以我们假设它会选择mailbox1,然后thread2将选择mailbox2,thread3将选择mailbox3, thread4将选择mailbox4而thread5将选择mailbox5,现在当thread1(具有已定义的特定时间段)将自由时,它应该是pickbox6 - mailbox10,任何尚未读取的人都不应该从mailbox1中选择任何邮箱 - mailbox5 ,直到所有尚未阅读的邮箱。
哦,我明白了。一种解决方案是让一个调度线程每隔一段时间都在睡觉和醒来,以查看邮箱是否有任何邮件。如果他们这样做,那么它将一个作业服务到线程池,以便读取该邮箱。一旦读取了邮箱,该线程就会返回并要求下一个邮箱进行处理。调度线程将继续将邮箱添加到线程池,直到它被告知停止。
如果EmailProcessor
中有很多上下文,那么你可以拥有你的线程池,但是他们可以使用BlockingQueue<File>
消息来告诉他们需要注意哪些邮箱。
答案 1 :(得分:1)
如何简单地创建任务的并发(或同步,在这种情况下无关紧要)集合(可能是队列)。每项任务都将从电子邮件帐户加载所需的数据。然后让每个线程从集合中获取任务,直到它为空。
每个线程都会引用此集合并对其进行循环。虽然集合不是空的,但从中获取任务并处理它。
答案 2 :(得分:1)
跟踪已阅读的电子邮件帐户。 例如,定义类似的东西,
//total number of email accounts that need to be read.
private int noOfEmails=10;
//the thread pool that is used to read the emails
private ExecutorService threadPool = Executors.newFixedThreadPool(5);
//the tracker array that keeps track of the emails that
//are already read. This array is cleared only after all 10
//emails are read.
private ArrayList<String> emailTracker=new ArrayList<String>(noOfEmails);
//any changes to emailTracker should be synchronized as
//this is a common data shared between all 5 threads.
private Object syncObject=new Object();
在Runnable实现中,检查emailTracker是否包含您的电子邮件帐户标识符,如果是这样,表明它已被读取,请返回并等待emailTracker被清除。当读取所有10个电子邮件帐户时,它将被清除。
if(emailTracker.contains(email.identifier))
{
return;
}
//read email.
email.read();
//simple synchronization.
synchronized (syncObject)
{
//read email
emailTracker.add(email.identifier);
//if all emails are read, clear the tracker
//This will allow reading of all the emails
//once again.
if(emailTracker.size()==noOfEmails)
{
emailTracker.clear();
}
}
答案 3 :(得分:1)
执行器可能不是这里的最佳解决方案,但为了简单起见,我将使用Gray代码的变体。为了连续扫描您的10个邮箱,您可以执行以下操作,但您必须添加一些代码来处理干净终止:
// Create one semaphore per mailbox
Semaphore semaphores[] = new Semaphore[10]
for (int s = 0; s < semaphores.length; s ++) {
semaphores[s] = new Semaphore(1);
}
// create a thread pool with 5 workers
ExecutorService threadPool = Executors.newFixedThreadPool(5);
// submit all 10 user email accounts to the pool to be processed in turn
for (int i = 0; i < 5; i ++) {
threadPool.submit(userEmailsToProcess, semaphores);
}
// once we have submitted all jobs to the thread pool, it should be shutdown
threadPool.shutdown();
...
// here's our runnable class which does the actual work
public class EmailProcessor implements Runnable {
private UserEmail userEmailToProcess[];
private Semaphore semaphores[];
public MyJobProcessor(UserEmail userEmailToProcess[], Semaphore semaphores[]) {
this.userEmailsToProcess = userEmailToProcess;
this.semaphores = semaphores;
}
public void run() {
while (true) { // you could use a semaphore here to test program termination instead
for (int s = 0; s < semaphores.size; s ++) {
if (semaphores[s].tryAcquire()) {
UserEmail email = userEmailToProcess[s];
// read the user email
…
semaphores[s].release();
}
}
}
}
}
这是一个快速而肮脏的解决方案,不是100%公平,但它适用于任意数量的线程和邮箱。在您的特殊情况下,有10个电子邮件和5个工作人员,您可以让每个线程连续扫描邮箱的子集,即,thread1检查mailbox1然后mailbox2,线程2检查mailbox3然后mailbox4,...这样你可以没有信号量,因为那里没有争论
答案 4 :(得分:0)
Sanju我相信你想以下面的循环方式执行它们:
线程1:1,6等等 线程2:2,7 线程3:3,8 线程4:4,9 线程5:5,10
首先,如果你想按照这样的顺序执行它们,那么这不是什么线程。第二,我不认为线程池是可能的。如果您仍然需要它们,那么这里是我以循环方式执行线程的解决方案,您可以根据需要进行更改: 公共类EmailRoundRobin { public Object [] locks;
private static class EmailProcessor implements Runnable {
private final Object currentLock;
private final Object nextLock;
private UserEmail userEmail;
public EmailProcessor (UserEmail userEmail,, Object currentLock, Object nextLock) {
this.userEmail = userEmail;
this.currentLock = currentLock;
this.nextLock = nextLock;
}
@Override
public void run() {
try {
work = //reading email
while ( work != null) {
try {
currentLock.wait();
// Do your work here.
}
catch(InterruptedException e) {}
synchronized(nextLock) {
nextLock.notify();
}
}//while ends
} catch (IOException e) {
e.printStackTrace();
}
synchronized(nextLock) {
nextLock.notify(); /// Ensures all threads exit at the end
}
}
public EmailRoundRobin(int numberOfAccountsToRead) {
locks = new Object[numberOfAccountsToRead];
//Initialize lock instances in array.
for(i = 0; i < numberOfAccountsToRead; ++i) locks[i] = new Object();
//Create threads
int j;
for(j=0; j<(numberOfAccountsToRead-1); j++ ){
Thread linePrinterThread = new Thread(new EmailProcessor(emailInfo + "Temp" + j,locks[j],locks[j+1]));
linePrinterThread.start();
}
Thread lastLinePrinterThread = new Thread(new EmailProcessor(emailInfo + "Temp" + j,locks[numberOfFilesToRead-1],locks[0]));
lastLinePrinterThread.start();
}
public void startProcessing() {
synchronized (locks[0]) {
locks[0].notify();
}
}
public static void main(String[] args) {
EmailRoundRobin emailRoundRobin = new EmailRoundRobin(4);
emailRoundRobin.startPrinting();
}
}
我从[这个问题](Running threads in round robin fashion in java)的回答中得到了这个结论!有类似的要求。在该答案中也提到了使用Phaser的选项。
答案 5 :(得分:-2)
我自己得到了一个答案,非常简单,我使用的是ExecutorService,它只由它管理。