views:

496

answers:

4

I have a list of hosts in an array which represnt the servers available to do a particular job. Currently I simply iterate thru the list looking and establish comms with a host to check its not busy. If not I will send a job to it. This approach tends to mean that the first host in the list tends to get hot constanly with the load not balanced properly with the rest of the available hosts.

in pseudocode ..

for (Host h : hosts) {

    //checkstatus
    if status == job accepted break;

}

I'd like to balance this load properly between the hosts i.e first time host one is used 2nd time the method is used host 2. Just wondering that the most elegant solution to this is ??

Thanks W

+3  A: 

You can create a new kind of Iterable that provides round-robin iteration:

public class RoundRobin<T> implements Iterable<T> {
  private List<T> coll;
  private int index = 0;

  public RoundRobin(List<T> coll) { this.coll = coll; }

  public Iterator<T> iterator() { 
     return new Iterator<T> {
        private T t;

        public T next() {
           T res = t;
           index = (index + 1) % coll.size();
           t = coll.get(index);
           return res;
        }
        public boolean hasNext() { return true; }
        public void remove() { throw new UnsopportedOperationException(); }
     };
  }

}

You need to define your hosts as RoundRobin<Host>

Itay
Good solution. One small issue though: Performing coll.get(index) is expensive for some lists. I'd say maintaining an iterator and doing next on it, and getting a fresh iterator when you run out of elements is better.
Buhb
This is the kind of thing im after thanks Itay and Buhb
wmitchell
+1  A: 

If the list is mutable and the cost of editing it is negligible compared to I/O with the hosts, you can just rotate it:

List<String> list = Arrays.asList("one", "two", "three");
Collections.rotate(list, -1);
System.out.println(list);
McDowell
+2  A: 

Google collections has a utility method Iterators.cycle(Iterable<T> iterable) that does what you want.

Buhb
A: 

If you are creating an Iterator, best to create a defensive copy first and have the iterator work on that.

return new MyIterator(ImmutableList.<T>of(list));
gpampara
`of` should be `copyOf`; otherwise you have a list that contains as its sole element a reference to the original list.
Kevin Bourrillion
Yes. Sorry, rather a bad typo there
gpampara