Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 2 of 6
Now let's imagine that I want to execute two complex tasks concurrently, each broken up into chunks. I do this simply by interleaving the two tasks, as illustrated in Figure 3.

Figure 3. Two tasks interleaved
I can implement this strategy as follows:
Runnable[] first_task = new Runnable[]
{
new Runnable(){ public void run(){ /* do task 1, chunk 1 here */ } },
new Runnable(){ public void run(){ /* do task 1, chunk 2 here */ } },
new Runnable(){ public void run(){ /* do task 1, chunk 3 here */ } },
new Runnable(){ public void run(){ /* do task 1, chunk 4 here */ } },
};
Runnable[] second_task = new Runnable[]
{
new Runnable(){ public void run(){ /* do task 2, chunk 1 here */ } },
new Runnable(){ public void run(){ /* do task 2, chunk 2 here */ } },
new Runnable(){ public void run(){ /* do task 2, chunk 3 here */ } },
new Runnable(){ public void run(){ /* do task 2, chunk 4 here */ } },
};
for( int i = 0; i < first_task.length; ++i )
{ first_task[i].run();
second_task[i].run();
Thread.getCurrentThread().yield();
}
The foregoing example isn't a particularly good general strategy because the loop has to know individually about each array, but I can also merge the two arrays into one large array before entering the loop:
Runnable[] both_tasks = new Runnable[]
{
new Runnable(){ public void run(){ /* do task 1, chunk 1 here */ } },
new Runnable(){ public void run(){ /* do task 2, chunk 1 here */ } },
new Runnable(){ public void run(){ /* do task 1, chunk 2 here */ } },
new Runnable(){ public void run(){ /* do task 2, chunk 2 here */ } },
new Runnable(){ public void run(){ /* do task 1, chunk 3 here */ } },
new Runnable(){ public void run(){ /* do task 2, chunk 3 here */ } },
new Runnable(){ public void run(){ /* do task 1, chunk 4 here */ } },
new Runnable(){ public void run(){ /* do task 2, chunk 4 here */ } },
};
for( int i = 0; i < first_task.length; ++i )
{ both_tasks[i].run();
Thread.getCurrentThread().yield();
}
Note that I've interleaved the operations: task 1, chunk 1 runs before task 2, chunk 1; then task 2, chunk 2 runs, and so
forth. What's going on here, at least with respect to the two tasks, is a lot like what you'd see in a preemptive scheduler
on a concurrent system (one CPU) in which each task was executing on its own thread. The big difference is that each chunk
has control over when it gets "preempted." You don't lose control until you return from the run() method that implements the chunk. In fact, this behavior is a lot like a multithreading cooperative system (in which you
don't give up control until you explicitly yield to another thread). Because of the explicit yielding of control, you don't
have to synchronize any of the fields used by either task, provided that you divide up the chunks carefully. You can always
leave any referenced objects in a stable state when you give up control.
Synchronous dispatching is surprisingly useful, especially when speed is of the essence. All the chunks are executing on a single OS-level thread. There is no synchronization overhead at all, and no expensive context swaps into the OS kernel. The main downside is that it's sometimes tricky to break up a single task into neat chunks.