Here is a simple example:
ThreadTest.java
public class ThreadTest { public static void main(String [] args) { MyThread t1 = new MyThread(0, 3, 300); MyThread t2 = new MyThread(1, 3, 300); MyThread t3 = new MyThread(2, 3, 300); t1.start(); t2.start(); t3.start(); } }
Mythread.java
public class MyThread extends Thread { private int startIdx, nThreads, maxIdx; public MyThread(int s, int n, int m) { this.startIdx = s; this.nThreads = n; this.maxIdx = m; } @Override public void run() { for(int i = this.startIdx; i < this.maxIdx; i += this.nThreads) { System.out.println("[ID " + this.getId() + "] " + i); } } }
And some conclusion:
[ID 9] 1 [ID 10] 2 [ID 8] 0 [ID 10] 5 [ID 9] 4 [ID 10] 8 [ID 8] 3 [ID 10] 11 [ID 10] 14 [ID 10] 17 [ID 10] 20 [ID 10] 23
Explanation. Each MyThread object tries to print numbers from 0 to 300, but they are only responsible for certain areas of this range. I decided to break it down by index, with each thread jumping forward in the number of threads. So, t1 has an index of 0, 3, 6, 9, etc.
Now, without I / O, trivial calculations like this might still look like threads being executed sequentially, so I just showed the first part of the output. On my computer, after this, the output stream with identifier 10 ends immediately, and then 9, then 8. If you put an expectation or profitability, you can see it better:
Mythread.java
System.out.println("[ID " + this.getId() + "] " + i); Thread.yield();
And the conclusion:
[ID 8] 0 [ID 9] 1 [ID 10] 2 [ID 8] 3 [ID 9] 4 [ID 8] 6 [ID 10] 5 [ID 9] 7
Now you can see the execution of each thread, give up control at an early stage and the next execution.