我们如何以循环方式使用multithreading?

我想以multithreading的方式阅读10个邮件帐户的未读邮件。

但是如果线程池大小为5,那么将从线程池中使用5个线程。 每个线程将读取一个邮件帐户。 因此,一旦Thread_1读取了第一个邮箱,它应该读取mailbox_6。 然后线程2将读取mailbox_7。

当所有邮件帐户都被读取一次后,该循环将从第一个邮件帐户开始。

我们怎么能在java中这样做?

这应该很容易。 您创建一个包含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或者告诉他们什么邮箱需要注意的东西。

跟踪已读取的电子邮件帐户。 例如,定义这样的东西,

 //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 emailTracker=new ArrayList(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(); } } 

如何简单地创建任务的并发(或同步,在这种情况下无关紧要)集合(可能是队列)。 每个任务都将从电子邮件帐户加载所需的数据。 然后让每个线程从集合中获取任务,直到它为空。

每个线程都将引用此集合,并对其进行循环。 虽然集合不是空的,但从中获取任务并处理它。

执行者可能不是这里的最佳解决方案,但为了简单起见,我将使用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,...这样你可以没有信号量,因为那里没有争议

Sanju我相信你想以下面的循环方式执行它们:

Thread1:1,6等等Thread2:2,7 Thread3:3,8 Thread4:4,9 Thread5:5,10

首先,如果你想按照这样的顺序执行它们,这不是什么线程的意思。 其次我不认为线程池是可能的。 如果您仍然想要它们,那么这里是我以循环方式执行线程的解决方案,您可以根据需要进行更改:公共类EmailRoundRobin {public Object []锁定;

  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(); } 

}

我从[这个问题]的回答中得到了这个( 在java中以循环方式运行线程 )! 有类似的要求。 在该答案中也提到了使用Phaser的选项。

我自己得到了一个答案,非常简单,我使用了ExecutorService,它只由它管理。