2012-07-30 4 views
0

10 개의 메일 계정의 읽지 않은 메일을 멀티 스레드 방식으로 읽으 려합니다.어떻게 멀티 스레드를 라운드 로빈 방식으로 사용할 수 있습니까?

그러나 스레드 풀 크기가 5이면 스레드 풀에서 5 개의 스레드가 사용됩니다. 각 스레드는 하나의 메일 계정을 읽습니다. 따라서 Thread_1이 첫 번째 메일 박스를 읽은 후에는 mailbox_6을 읽어야합니다. 그런 다음 스레드 2는 mailbox_7을 읽습니다.

모든 메일 계정을 한 번 읽으면 첫 번째 메일 계정부터주기가 시작됩니다.

어떻게하면 자바에서이 작업을 수행 할 수 있습니까?

+0

@Sanju의 문제에 대한 구체적인 내용을 여전히 이해할 수 없습니다. 더 자세한 내용을 추가 할 수 있습니까? 아래 내 대답에서 사서함은 1-5, 6-10으로 처리됩니다. 그런 다음 지연 후 1-5 번을 처리하고 처음 처리 한 후에 1-5 번을 원하니? 6-10과 동일합니까? – Gray

+0

도움이된다면 제 대답을 수락하는 것을 잊지 마십시오. – Gray

답변

4

이것은 매우 쉬워야합니다. 당신은 5 개 스레드와 고정 스레드 풀을 만든 다음이 풀에 10 일 제출 - 1을 각 사용자의 이메일 계정 당 다음 UserEmail 클래스는 "읽기"하는 이메일의 파일 이름을 잡을 수

// 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 
     ... 
    } 
} 

또는 어카운트 이름 또는 무언가. 그것은 읽어야 할 메일 계정과 메일을 나타내는 방법을 이해하는 데 달려 있습니다.

는 [[코멘트에서 :]]

내가 지금은 스레드 풀에서 5 스레드를, 그래서 thread1은 가져옵니다 ..의 Mailbox1 ... mailbox10 추천 사서함이있는 사서함 때문에 가정 할 수 있습니다 mailbox1을 선택하면 thread2는 mailbox2를 선택하고, thread3는 mailbox3을 선택하고, thread4는 mailbox4를 선택하고, thread5는 mailbox5를 선택합니다. thread1 (이미 정의 된 특정 기간이 있음)이 해제되면 free가 선택됩니다. mailbox6 - mailbox10, anyone 읽지 않은 메일은 아직 읽지 않은 모든 편지함까지 mailbox1 - mailbox5의 편지함을 선택해서는 안됩니다.

아, 알 수 있습니다. 한 가지 해결책은 메일 함이 있는지 모든 메일을 확인하기 위해 자주 잠들고 일어나는 디스패치 스레드를 만드는 것입니다. 그럴 경우 해당 사서함의 스레드 풀에 작업을 적용하여 읽을 수 있습니다. 사서함이 읽혀지면 스레드는 다시 돌아가서 처리 할 다음 사서함을 요청합니다. 디스패치 스레드는 중지하라는 메시지가 표시 될 때까지 스레드 풀에 사서함을 계속 추가합니다.

EmailProcessor에 많은 컨텍스트가있는 경우 스레드 풀을 사용할 수 있지만 BlockingQueue<File> 또는 무엇이 메일 박스에주의해야하는지 알 수 있습니다.

+0

안녕하세요 회색, 귀하의 소중한 시간과 답장을 보내 주셔서 감사합니다,하지만 난 내 질문을 얻을 수있을 것 같아요, 뭐든 u는 단순히 5 스레드를 실행하고 각 스레드는 별도의 메일 계정을 가져올 것입니다,하지만 나는 라운드 로빈 방법으로 가져오고 싶습니다, 10 개의 사서함이있는 경우 첫 번째 스레드가 첫 번째 사서함을 가져온 다음 10 개의 사서함을 한 번 읽은 후에 첫 번째 사서함을 다시 읽습니다. 그 시간까지는 첫 번째 사서함을 읽지 않아야합니다. – Sanju

+0

아직 @ 삼주를 이해하지 못합니다. 따라서 모든 편지함을 읽으려면 먼저 그 중 하나를 다시 읽으십시오. 풀 종료를 기다리는 종료시에'threadPool.awaitTermination (Long.MAX_VALUE, TimeUnit.MILLISECONDS);'콜을 넣을 수있다. 너가 원하는게 그거야? – Gray

+0

안녕하세요 @ 그레이, 그래, 다시 고마워, 난 지금 이해할 수있는 것 같아, 내가 10 사서함을 가지고 같은 ... mailbox1 ... mailbox10, 이제 스레드 풀에서 5 스레드를 가지고 있으므로 thread1 어떤 사서함 가져올 것이다 그래서 그것을 추측 할 수 있습니다. mailbox1을 선택하면 thread2는 mailbox2를 선택하고, thread3는 mailbox3을 선택하고, thread4는 mailbox4를 선택하고, thread5는 mailbox5를 선택합니다. thread1 (이미 정의 된 특정 기간이 있음)이 해제되면 free가 선택됩니다. mailbox6 - mailbox10, anyone 읽지 않은 메일은 아직 읽지 않은 모든 편지함까지 mailbox1 - mailbox5의 편지함을 선택해서는 안됩니다. – Sanju

-2

나는 매우 간단하다. 나는 ExecutorService를 사용했고, 그것만이 관리했다.

1

단순히 작업 (예 : 대기열)과 동시 (동기화 된, 많은 경우 중요하지 않음) 컬렉션을 만드는 방법은 무엇입니까? 각 작업은 이메일 계정에서 필요한 데이터를로드합니다. 그런 다음 각 스레드가 비어있을 때까지 콜렉션에서 태스크를 가져 오도록하십시오.

각 스레드는이 컬렉션에 대한 참조를 가지며 이에 대한 루프를 수행합니다. 컬렉션이 비어 있지 않으면 컬렉션에서 작업을 가져 와서 처리합니다.

1

읽은 전자 메일 계정을 추적하십시오. 예를 들어 는 emailTracker 이메일 계정 식별자를 포함하는 경우 그래서 그것을 읽고 이미 의미 있는지 확인, 그래서 돌아가 emailTracker이 해제 될 때까지 기다린 Runnable를 구현에서는

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

, 이런 일을 정의합니다.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(); 
      } 

     } 
1

여기서 Executors가 최적의 솔루션이 아닐 수도 있지만 간단히하기 위해 Gray 코드에 변형을 사용합니다. 그것을

100 % 공정 신속하고 더러운 해결책이 아니다
// 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(); 
       } 
      } 
     } 
    } 
} 

이되는하지만 : 당신이 깨끗한 종료를 처리하기 위해 몇 가지 코드를 추가해야하지만 지속적으로 10 개 사서함을 검색하려면 다음을 수행 할 수 있습니다 많은 수의 스레드와 사서함에서 작동합니다. 10 개의 이메일과 5 명의 작업자가있는 특별한 경우에는 각 스레드가 사서함의 하위 집합을 계속 검색 할 수 있습니다. 즉, thread1은 mailbox1을 확인한 다음 mailbox2를 검사하고 스레드 2는 mailbox3을 검사 한 다음 mailbox4를 검사합니다.이 방법을 사용하면 세마포없이 수행 할 수 있습니다.

Thread1 : 경합

0

SANJU 난 당신이 다음 라운드 로빈 방식으로이를 실행하려는 생각하지 않습니다 1,6하고 그렇게 Thread2에 : 2,7 Thread3 : 3,8 Thread4 : 4,9 Thread5 : 5,10

먼저 스레드를 실행하려면 무엇을해야합니까? 그런 순서로. 둘째 스레드 풀에서는 가능하지 않다고 생각합니다. 만약 당신이 여전히 그들을 원한다면 여기에 당신이 필요에 따라 변경할 수 있습니다 라운드 로빈 방식으로 스레드를 실행하기위한 내 솔루션입니다 : public class EmailRoundRobin { public Object [] locks; 내가 [이 질문] (Running threads in round robin fashion in java)에 내 대답에서이 촬영 한

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

}! 비슷한 요구 사항을 가지고 있었다. Phaser를 사용하는 옵션도 있습니다.