├── src └── threads │ ├── example1 │ └── InstantiateUsingOnlyThread.java │ ├── example2 │ └── InstantiateUsingRunnable.java │ ├── example18 │ └── HandlingExceptionsInThreadAPI.java │ ├── example5 │ └── SingleThreadPoolExample.java │ ├── example13 │ └── TerminateBlockedTaskUsingThreadAPI.java │ ├── example6 │ └── CachedThreadPoolExample.java │ ├── example16 │ └── TerminateBlockedTaskUsingThreadAPI.java │ ├── example12 │ └── TerminateTaskUsingThreadAPI.java │ ├── example4 │ └── FixedThreadPoolExample.java │ ├── example23 │ └── SchedulingTasksWithTimers.java │ ├── example11 │ └── TerminateTaskUsingFlagThreadAPI.java │ ├── example10 │ └── CheckIfTaskIsDoneUsingExecutors.java │ ├── example9 │ └── CheckIfThreadIsAliveUsingThreadAPI.java │ ├── example3 │ └── ReturnValueUsingThreadAPI.java │ ├── example7 │ └── ReturnValuesUsingCallable.java │ ├── example15 │ └── TerminateTaskUsingFuture.java │ ├── example19 │ └── HandlingExceptionsInExecutors.java │ ├── example24 │ └── SchedulingTasksWithScheduledThreadPool.java │ ├── example17 │ └── TerminateAllTasksInExecutorService.java │ ├── example8 │ └── NamingThreadUsingExecutors.java │ ├── example14 │ └── TerminateTaskUsingFlagExecutors.java │ ├── example20 │ └── WatingForThreadsToFinishUsingJoin.java │ ├── example22 │ └── WatingTasksToFinishesAndGettingResultsUsingExecutors.java │ └── example21 │ └── GetResultFromTaskUsingJoinsThreadAPI.java └── README.md /src/threads/example1/InstantiateUsingOnlyThread.java: -------------------------------------------------------------------------------- 1 | package threads.example1; 2 | 3 | /* 4 | * Instantiate a thread by using Thread class. 5 | */ 6 | 7 | public class InstantiateUsingOnlyThread { 8 | 9 | public static void main(String[] args) { 10 | 11 | System.out.println("Thread main started"); 12 | 13 | Thread thread1 = new MyTask("any data that the thread may need to process"); 14 | Thread thread2 = new MyTask("any data that the thread may need to process"); 15 | thread1.start(); 16 | thread2.start(); 17 | 18 | System.out.println("Thread main finished"); 19 | } 20 | } 21 | 22 | class MyTask extends Thread { 23 | private String anyData; 24 | 25 | public MyTask(String anyData) { 26 | this.anyData = anyData; 27 | } 28 | 29 | public void run() { 30 | for (int i = 0; i < 10; i++) { 31 | System.out.println("[" + Thread.currentThread().getName() + "] [data=" + this.anyData + "] Message " + i); 32 | try { 33 | Thread.sleep(200); 34 | } catch (InterruptedException e) { 35 | e.printStackTrace(); 36 | } 37 | } 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/threads/example2/InstantiateUsingRunnable.java: -------------------------------------------------------------------------------- 1 | package threads.example2; 2 | 3 | /* 4 | * Instantiate a thread by using Runnable interface 5 | */ 6 | 7 | public class InstantiateUsingRunnable { 8 | 9 | public static void main(String[] args) { 10 | 11 | System.out.println("Thread main started"); 12 | 13 | Thread thread1 = new Thread(new MyTask("any data that the thread may need to process")); 14 | Thread thread2 = new Thread(new MyTask("any data that the thread may need to process")); 15 | thread1.start(); 16 | thread2.start(); 17 | 18 | System.out.println("Thread main finished"); 19 | } 20 | } 21 | 22 | class MyTask implements Runnable { 23 | private String anyData; 24 | 25 | public MyTask(String anyData) { 26 | this.anyData = anyData; 27 | } 28 | 29 | public void run() { 30 | for (int i = 0; i < 10; i++) { 31 | System.out.println("[" + Thread.currentThread().getName() + "] [data=" + this.anyData + "] Message " + i); 32 | try { 33 | Thread.sleep(200); 34 | } catch (InterruptedException e) { 35 | e.printStackTrace(); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/threads/example18/HandlingExceptionsInThreadAPI.java: -------------------------------------------------------------------------------- 1 | package threads.example18; 2 | 3 | import java.lang.Thread.UncaughtExceptionHandler; 4 | 5 | /* 6 | * Instantiates an UncaughtExceptionHandler to handle exceptions that may rise in 7 | * all the threads of the application (including those in a Thread Pool) 8 | * 9 | * It's also possible to set an UncaughtExceptionHandler directly to an specific thread object. 10 | * 11 | * You may also use a combination of both strategies as specific handlers overrides the global one 12 | */ 13 | 14 | public class HandlingExceptionsInThreadAPI { 15 | 16 | public static void main(String[] args) { 17 | 18 | System.out.println("Thread main started"); 19 | 20 | Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() { 21 | public void uncaughtException(Thread t, Throwable e) { 22 | System.out.println("Handling the Exception occured in thread " + t.getName()); 23 | } 24 | }); 25 | 26 | new MyTask().start(); 27 | new MyTask().start(); 28 | 29 | System.out.println("Thread main finished"); 30 | } 31 | } 32 | 33 | class MyTask extends Thread { 34 | public void run() { 35 | throw new RuntimeException(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java Thread Simple Examples 2 | 3 | This repository contains more than 20 simple examples with explanations on how to use Java Thread API and Executors Framework. Currently, the following subjects are covered: 4 | 5 | - Running tasks from Thread and Runnable 6 | - Strategies for returning values from Threads and Runnable tasks 7 | - wait(), notify(), interrupt(), join(), isAlive()... 8 | - Creating Thread Pools (FixedThreadPool, CachedThreadPool, SingleThreadPool, ScheduledThreadPool...) 9 | - Submiting tasks to ExecutorService 10 | - Returning values from tasks using Callable and Future 11 | - Naming threads and creating deamon threads in a thread pool implementing ThreadFactory interface 12 | - Terminating tasks using Thread API 13 | - Terminating tasks using Future 14 | - Handling exceptions in normal threads implementing UncaughtExceptionHandler interface 15 | - Handling exceptions in threads on a thread pool implementing UncaughtExceptionHandler interface 16 | - Managing tasks termination using CountDownLatch 17 | - Running scheduled tasks using Timer and TimerTask 18 | - Running scheduled tasks using ScheduledThreadPool 19 | 20 | Of course there are much more than this to cover (such as Fork/Join Framework). Feel free to fork this project and contribute with more simple thread examples! 21 | 22 | -------------------------------------------------------------------------------- /src/threads/example5/SingleThreadPoolExample.java: -------------------------------------------------------------------------------- 1 | package threads.example5; 2 | 3 | import java.util.concurrent.ExecutionException; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.Executors; 6 | 7 | /* 8 | * Instantiates a thread pool with a single thread 9 | * All tasks are executed sequentially by the same thread 10 | */ 11 | 12 | public class SingleThreadPoolExample { 13 | 14 | public static void main(String[] args) throws InterruptedException, ExecutionException { 15 | 16 | System.out.println("Thread main started"); 17 | 18 | ExecutorService executorService = Executors.newSingleThreadExecutor(); 19 | executorService.execute(new MyTask()); 20 | executorService.execute(new MyTask()); 21 | executorService.execute(new MyTask()); 22 | executorService.execute(new MyTask()); 23 | executorService.execute(new MyTask()); 24 | 25 | executorService.shutdown(); 26 | 27 | System.out.println("Thread main finished"); 28 | } 29 | } 30 | 31 | class MyTask implements Runnable { 32 | public void run() { 33 | for (int i = 0; i < 10; i++) { 34 | System.out.println("[" + Thread.currentThread().getName() + "] " + "Message " + i); 35 | try { 36 | Thread.sleep(200); 37 | } catch (InterruptedException e) { 38 | e.printStackTrace(); 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/threads/example13/TerminateBlockedTaskUsingThreadAPI.java: -------------------------------------------------------------------------------- 1 | package threads.example13; 2 | 3 | /* 4 | * Terminates a TASK (not the Thread itself) by using the Thread.interrupt() method on the thread 5 | * while its sleeping (blocked state). 6 | * 7 | * If you'd like to only terminate the task after the sleep finishes, instead of 'break' in the 8 | * catch block, you can set a flag and check for this flag after. Something like: 9 | * 10 | * catch() { 11 | * interruptedTask=true; 12 | * } 13 | * 14 | * if (Thread.interrupted() || interruptedTask) 15 | * break; 16 | */ 17 | 18 | public class TerminateBlockedTaskUsingThreadAPI { 19 | 20 | public static void main(String[] args) { 21 | 22 | System.out.println("Thread main started"); 23 | 24 | MyTask task1 = new MyTask(); 25 | Thread thread1 = new Thread(task1); 26 | thread1.start(); 27 | thread1.interrupt(); 28 | 29 | System.out.println("Thread main finished"); 30 | } 31 | } 32 | 33 | class MyTask implements Runnable { 34 | public void run() { 35 | for (int i = 0; i < 10; i++) { 36 | System.out.println("[" + Thread.currentThread().getName() + "] Message " + i); 37 | 38 | try { 39 | Thread.sleep(1l); 40 | } catch (InterruptedException e) { 41 | System.out.println("Interrupting the thread while it was sleeping..."); 42 | break; 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/threads/example6/CachedThreadPoolExample.java: -------------------------------------------------------------------------------- 1 | package threads.example6; 2 | 3 | import java.util.concurrent.ExecutionException; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.Executors; 6 | 7 | /* 8 | * Instantiates a thread pool that allocates as many threads as tasks are given 9 | * 10 | * Create more tasks and execute it again. Note that there are no queued tasks as the 11 | * pool grows when there are no available threads to run the tasks 12 | */ 13 | 14 | public class CachedThreadPoolExample { 15 | 16 | public static void main(String[] args) throws InterruptedException, ExecutionException { 17 | 18 | System.out.println("Thread main started"); 19 | 20 | ExecutorService executorService = Executors.newCachedThreadPool(); 21 | executorService.execute(new MyTask()); 22 | executorService.execute(new MyTask()); 23 | executorService.execute(new MyTask()); 24 | executorService.execute(new MyTask()); 25 | executorService.execute(new MyTask()); 26 | 27 | executorService.shutdown(); 28 | 29 | System.out.println("Thread main finished"); 30 | } 31 | } 32 | 33 | class MyTask implements Runnable { 34 | public void run() { 35 | for (int i = 0; i < 10; i++) { 36 | System.out.println("[" + Thread.currentThread().getName() + "] " + "Message " + i); 37 | try { 38 | Thread.sleep(200); 39 | } catch (InterruptedException e) { 40 | e.printStackTrace(); 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/threads/example16/TerminateBlockedTaskUsingThreadAPI.java: -------------------------------------------------------------------------------- 1 | package threads.example16; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.Future; 6 | 7 | /* 8 | * Terminates a blocking TASK by using the Future.cancel(true) method. 9 | * 10 | * If you'd like only to terminate the task after the sleep finishes, instead of 'break' in the 11 | * catch block, you can set a flag and check for this flag after. Something like: 12 | * 13 | * catch() { 14 | * interruptedTask=true; 15 | * } 16 | * 17 | * if (Thread.interrupted() || interruptedTask) 18 | * break; 19 | */ 20 | 21 | public class TerminateBlockedTaskUsingThreadAPI { 22 | 23 | public static void main(String[] args) throws InterruptedException { 24 | 25 | System.out.println("Thread main started"); 26 | 27 | ExecutorService executorService = Executors.newCachedThreadPool(); 28 | Future result = executorService.submit(new MyTask()); 29 | 30 | Thread.sleep(500l); 31 | result.cancel(true); 32 | 33 | executorService.shutdown(); 34 | 35 | System.out.println("Thread main finished"); 36 | } 37 | } 38 | 39 | class MyTask implements Runnable { 40 | public void run() { 41 | for (int i = 0; i < 10000; i++) { 42 | System.out.println("[" + Thread.currentThread().getName() + "] Message " + i); 43 | 44 | try { 45 | Thread.sleep(1l); 46 | } catch (InterruptedException e) { 47 | System.out.println("Interrupting the thread while it was sleeping..."); 48 | break; 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/threads/example12/TerminateTaskUsingThreadAPI.java: -------------------------------------------------------------------------------- 1 | package threads.example12; 2 | 3 | /* 4 | * Terminates a TASK (not the Thread itself) by using the Thread.interrupt() method on the thread. 5 | * Note that the task will not terminate immediately as terminating the task depends on 6 | * the execution reaches the line "if (Thread.interrupted())" 7 | * 8 | * As in the Thread API a thread basically executes only one task (it's not 9 | * reusable), once the task is finished the thread will finish as well. 10 | * Again: note that the here the TASK is being terminated, not the thread. 11 | */ 12 | 13 | public class TerminateTaskUsingThreadAPI { 14 | 15 | public static void main(String[] args) { 16 | 17 | System.out.println("Thread main started"); 18 | 19 | MyTask task1 = new MyTask(); 20 | Thread thread1 = new Thread(task1); 21 | thread1.start(); 22 | 23 | thread1.interrupt(); 24 | 25 | System.out.println("Thread main finished"); 26 | } 27 | } 28 | 29 | class MyTask implements Runnable { 30 | public void run() { 31 | for (int i = 0; i < 100000; i++) { 32 | System.out.println("[" + Thread.currentThread().getName() + "] Message " + i); 33 | 34 | if (Thread.interrupted()) { 35 | System.out.println("This thread was interruped by someone calling thisThread.interrupt()"); 36 | System.out.println("Cancelling task running in thread " + Thread.currentThread().getName()); 37 | System.out.println("Just illustrating that after Thread.interrupted() call, JVM reset the interrupted value to: " + Thread.interrupted()); 38 | break; 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/threads/example4/FixedThreadPoolExample.java: -------------------------------------------------------------------------------- 1 | package threads.example4; 2 | 3 | import java.util.concurrent.ExecutionException; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.Executors; 6 | 7 | /* 8 | * Instantiates a fixed thread pool with 5 threads. When executing 5 tasks 9 | * simultaneously, each task will be assigned to one of the five available threads 10 | * 11 | * Change the thread pool size to 1 and execute the example again. Note that 12 | * now each task will be executed one by one on a sequential fashion 13 | * In this scenario, while first task is being executed the other 4 are queued 14 | */ 15 | 16 | public class FixedThreadPoolExample { 17 | 18 | public static void main(String[] args) throws InterruptedException, ExecutionException { 19 | 20 | System.out.println("Thread main started"); 21 | 22 | ExecutorService executorService = Executors.newFixedThreadPool(5); 23 | executorService.execute(new MyTask()); 24 | executorService.execute(new MyTask()); 25 | executorService.execute(new MyTask()); 26 | executorService.execute(new MyTask()); 27 | executorService.execute(new MyTask()); 28 | 29 | executorService.shutdown(); 30 | 31 | System.out.println("Thread main finished"); 32 | } 33 | } 34 | 35 | class MyTask implements Runnable { 36 | public void run() { 37 | for (int i = 0; i < 10; i++) { 38 | System.out.println("[" + Thread.currentThread().getName() + "] " + "Message " + i); 39 | try { 40 | Thread.sleep(200); 41 | } catch (InterruptedException e) { 42 | e.printStackTrace(); 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/threads/example23/SchedulingTasksWithTimers.java: -------------------------------------------------------------------------------- 1 | package threads.example23; 2 | 3 | import java.util.Date; 4 | import java.util.Timer; 5 | import java.util.TimerTask; 6 | import java.util.concurrent.CountDownLatch; 7 | 8 | /* 9 | * Executes a TimerTask (which implements Runnable) on a Ttimer that will run the task on a 10 | * SINGLE thread after 5 seconds 11 | * 12 | * It's also possible to use Timer.scheduleAtFixedRate to run the task repeatedly. In this case 13 | * You may want to set the Timer constructor to true in order to to make it run as a Deamon 14 | * 15 | * Also, blocks the main thread until the countdown reaches 0, that is, when the task is done 16 | * See the previous example to learn the CountDownLatch 17 | */ 18 | 19 | public class SchedulingTasksWithTimers { 20 | 21 | public static void main(String[] args) throws InterruptedException { 22 | System.out.println("Thread main started"); 23 | CountDownLatch countDownLatch = new CountDownLatch(1); 24 | 25 | Timer timer = new Timer(); 26 | System.out.println("Scheduling task to run after 5 seconds... " + new Date()); 27 | timer.schedule(new MyTask(countDownLatch), 5000); 28 | 29 | countDownLatch.await(); 30 | 31 | timer.cancel(); 32 | System.out.println("Thread main finished"); 33 | } 34 | } 35 | 36 | class MyTask extends TimerTask { 37 | 38 | private CountDownLatch countDownLatch; 39 | 40 | public MyTask(CountDownLatch countDownLatch) { 41 | this.countDownLatch = countDownLatch; 42 | } 43 | 44 | @Override 45 | public void run() { 46 | System.out.println("Executing the task at: " + new Date()); 47 | countDownLatch.countDown(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/threads/example11/TerminateTaskUsingFlagThreadAPI.java: -------------------------------------------------------------------------------- 1 | package threads.example11; 2 | 3 | /* 4 | * Terminates a TASK (not the Thread itself) by using a flag inside the task. 5 | * Note that the task will not terminate immediately. Comment the cancel() 6 | * invocation to see the task finishing its job. 7 | * 8 | * As in the Thread API a thread basically executes only one task (it's not 9 | * reusable), once the task is finished the thread will finish as well. 10 | * Again: note that the here the TASK is being terminated, not the thread. 11 | */ 12 | 13 | public class TerminateTaskUsingFlagThreadAPI { 14 | 15 | public static void main(String[] args) { 16 | 17 | System.out.println("Thread main started"); 18 | 19 | MyTask task1 = new MyTask(); 20 | Thread thread1 = new Thread(task1); 21 | thread1.start(); 22 | 23 | task1.cancel(); 24 | 25 | System.out.println("Thread main finished"); 26 | } 27 | } 28 | 29 | class MyTask implements Runnable { 30 | private volatile boolean cancelTask; 31 | 32 | public MyTask() { 33 | this.cancelTask = false; 34 | } 35 | 36 | public void run() { 37 | for (int i = 0; i < 10; i++) { 38 | System.out.println("[" + Thread.currentThread().getName() + "] Message " + i); 39 | try { 40 | Thread.sleep(200l); 41 | } catch (InterruptedException e) { 42 | e.printStackTrace(); 43 | } 44 | 45 | synchronized (this) { 46 | if (this.cancelTask) { 47 | System.out.println("Cancelling task running in thread " 48 | + Thread.currentThread().getName()); 49 | break; 50 | } 51 | } 52 | } 53 | } 54 | 55 | public void cancel() { 56 | synchronized (this) { 57 | this.cancelTask = true; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/threads/example10/CheckIfTaskIsDoneUsingExecutors.java: -------------------------------------------------------------------------------- 1 | package threads.example10; 2 | 3 | import java.util.concurrent.Callable; 4 | import java.util.concurrent.ExecutionException; 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | import java.util.concurrent.Future; 8 | 9 | /* 10 | * Checks whether the task has finished or not using Executors 11 | * When it's finished, print the result 12 | */ 13 | 14 | public class CheckIfTaskIsDoneUsingExecutors { 15 | 16 | public static void main(String[] args) throws InterruptedException, ExecutionException { 17 | 18 | System.out.println("Thread main started"); 19 | 20 | ExecutorService executorService = Executors.newSingleThreadExecutor(); 21 | Future result = executorService.submit(new SumFirstNumbers(50)); 22 | 23 | while (!result.isDone()) { 24 | System.out.println("Task is still processing"); 25 | Thread.sleep(500l); 26 | } 27 | 28 | System.out.println("Task is finished: " + result.isDone()); 29 | System.out.println("Task result is: " + result.get()); 30 | 31 | executorService.shutdown(); 32 | 33 | System.out.println("Thread main finished"); 34 | } 35 | } 36 | 37 | class SumFirstNumbers implements Callable { 38 | private int n; 39 | 40 | public SumFirstNumbers(int n) { 41 | this.n = n; 42 | } 43 | 44 | public Integer call() { 45 | int sum = 0; 46 | for (int i = 1; i <= n; i++) { 47 | System.out.println("[" + Thread.currentThread().getName() + "] Adding " + i); 48 | sum += i; 49 | try { 50 | Thread.sleep(200); 51 | } catch (InterruptedException e) { 52 | e.printStackTrace(); 53 | } 54 | } 55 | return sum; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/threads/example9/CheckIfThreadIsAliveUsingThreadAPI.java: -------------------------------------------------------------------------------- 1 | package threads.example9; 2 | 3 | /* 4 | * Checks whether a thread is alive or not. A thread is said to be alive 5 | * if it's started or waiting. An available thread in a thread pool 6 | * is on the waiting state, therefore it's alive 7 | * 8 | * The question is: when using the Executors, are we really interested 9 | * if threads are alive or if tasks are running? Think about it. 10 | */ 11 | 12 | public class CheckIfThreadIsAliveUsingThreadAPI { 13 | 14 | public static void main(String[] args) throws InterruptedException { 15 | 16 | System.out.println("Thread main started"); 17 | 18 | Thread thread1 = new Thread(new MyTask()); 19 | Thread thread2 = new Thread(new MyTask()); 20 | 21 | System.out.println("Thread1 is alive? " + thread1.isAlive()); 22 | System.out.println("Thread2 is alive? " + thread2.isAlive()); 23 | 24 | thread1.start(); 25 | thread2.start(); 26 | 27 | while (thread1.isAlive() || thread2.isAlive()) { 28 | System.out.println("Thread1 is alive? " + thread1.isAlive()); 29 | System.out.println("Thread2 is alive? " + thread2.isAlive()); 30 | Thread.sleep(500l); 31 | } 32 | 33 | System.out.println("Thread1 is alive? " + thread1.isAlive()); 34 | System.out.println("Thread2 is alive? " + thread2.isAlive()); 35 | 36 | System.out.println("Thread main finished"); 37 | } 38 | } 39 | 40 | class MyTask implements Runnable { 41 | public void run() { 42 | for (int i = 0; i < 10; i++) { 43 | System.out.println("[" + Thread.currentThread().getName() + "] Message " + i); 44 | try { 45 | Thread.sleep(200); 46 | } catch (InterruptedException e) { 47 | e.printStackTrace(); 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/threads/example3/ReturnValueUsingThreadAPI.java: -------------------------------------------------------------------------------- 1 | package threads.example3; 2 | 3 | /* 4 | * Returning values using Thread or Runnable is not straightforward. 5 | * One way is controlling the threads execution by using wait() and notify() methods 6 | */ 7 | 8 | public class ReturnValueUsingThreadAPI { 9 | 10 | public static void main(String[] args) throws InterruptedException { 11 | 12 | MyTask task1 = new MyTask(200l); 13 | Thread t1 = new Thread(task1); 14 | t1.start(); 15 | 16 | MyTask task2 = new MyTask(200l); 17 | Thread t2 = new Thread(task2); 18 | t2.start(); 19 | 20 | // if task1 is still executing, then it puts the caller thread [main] to wait 21 | // when it finishes, then notify() is called to wake up the caller thread 22 | // same for task 2 23 | System.out.println("Sum: " + task1.getSum()); 24 | System.out.println("Sum: " + task2.getSum()); 25 | } 26 | } 27 | 28 | class MyTask implements Runnable { 29 | private Long sleep; 30 | private volatile int sum; 31 | private boolean done = false; 32 | 33 | public MyTask(Long sleep) { 34 | this.sleep = sleep; 35 | } 36 | 37 | public void run() { 38 | for (int i = 1; i <= 10; i++) { 39 | System.out.println("[" + Thread.currentThread().getName() + "] Message " + i); 40 | this.sum += i; 41 | try { 42 | Thread.sleep(sleep); 43 | } catch (InterruptedException e) { 44 | e.printStackTrace(); 45 | } 46 | } 47 | done = true; 48 | synchronized (this) { 49 | this.notifyAll(); 50 | } 51 | } 52 | 53 | public int getSum() throws InterruptedException { 54 | synchronized (this) { 55 | if (!done) { 56 | System.out.println(Thread.currentThread().getName()+ " is waiting"); 57 | this.wait(); 58 | } 59 | } 60 | return this.sum; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/threads/example7/ReturnValuesUsingCallable.java: -------------------------------------------------------------------------------- 1 | package threads.example7; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.concurrent.Callable; 6 | import java.util.concurrent.ExecutionException; 7 | import java.util.concurrent.ExecutorService; 8 | import java.util.concurrent.Executors; 9 | import java.util.concurrent.Future; 10 | 11 | /* 12 | * Threads that returns values are better implemented in Java using Callable and Future 13 | * Use the Executors Framework to run a Callable task 14 | */ 15 | 16 | public class ReturnValuesUsingCallable { 17 | 18 | public static void main(String[] args) throws InterruptedException, ExecutionException { 19 | 20 | System.out.println("Thread main started"); 21 | 22 | ExecutorService executorService = Executors.newFixedThreadPool(5); 23 | List> returnedValues = executorService.invokeAll(Arrays.asList( 24 | new SumFirstNumbers(50), 25 | new SumFirstNumbers(40), 26 | new SumFirstNumbers(30), 27 | new SumFirstNumbers(20), 28 | new SumFirstNumbers(10))); 29 | 30 | for (Future value : returnedValues) { 31 | System.out.println(value.get()); 32 | } 33 | 34 | executorService.shutdown(); 35 | 36 | System.out.println("Thread main finished"); 37 | } 38 | } 39 | 40 | class SumFirstNumbers implements Callable { 41 | private int n; 42 | 43 | public SumFirstNumbers(int n) { 44 | this.n = n; 45 | } 46 | 47 | public Integer call() { 48 | int sum = 0; 49 | for (int i = 1; i <= n; i++) { 50 | System.out.println("[" + Thread.currentThread().getName() + "] Adding " + i); 51 | sum += i; 52 | try { 53 | Thread.sleep(200); 54 | } catch (InterruptedException e) { 55 | e.printStackTrace(); 56 | } 57 | } 58 | return sum; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/threads/example15/TerminateTaskUsingFuture.java: -------------------------------------------------------------------------------- 1 | package threads.example15; 2 | 3 | import java.util.concurrent.Callable; 4 | import java.util.concurrent.ExecutionException; 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | import java.util.concurrent.Future; 8 | 9 | /* 10 | * Terminates a TASK by using the Future.cancel(true) call. 11 | * Note that the task will not terminate immediately (that's why we put main to sleep for a while) 12 | * Comment the cancel() invocation to see the task finishing its job. 13 | * 14 | * Internally, it uses the same mechanism in one of the previous examples using Thread.interrupt() method. 15 | * 16 | * After the task is cancelled, the thread is again available in the thread pool. 17 | */ 18 | 19 | public class TerminateTaskUsingFuture { 20 | 21 | public static void main(String[] args) throws InterruptedException, ExecutionException { 22 | 23 | System.out.println("Thread main started"); 24 | 25 | ExecutorService executorService = Executors.newCachedThreadPool(); 26 | 27 | SumFirstNumbers sumTask = new SumFirstNumbers(500000); 28 | Future result = executorService.submit(sumTask); 29 | 30 | Thread.sleep(500l); 31 | result.cancel(true); 32 | 33 | executorService.shutdown(); 34 | 35 | System.out.println("Thread main finished"); 36 | } 37 | } 38 | 39 | class SumFirstNumbers implements Callable { 40 | private int n; 41 | 42 | public SumFirstNumbers(int n) { 43 | this.n = n; 44 | } 45 | 46 | public Integer call() { 47 | int sum = 0; 48 | for (int i = 1; i <= n; i++) { 49 | System.out.println("[" + Thread.currentThread().getName() + "] Adding " + i); 50 | sum += i; 51 | 52 | if (Thread.interrupted()) { 53 | System.out.println("Cancelling the task..."); 54 | return -1; 55 | } 56 | } 57 | return sum; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/threads/example19/HandlingExceptionsInExecutors.java: -------------------------------------------------------------------------------- 1 | package threads.example19; 2 | 3 | import java.lang.Thread.UncaughtExceptionHandler; 4 | import java.util.concurrent.ExecutionException; 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | import java.util.concurrent.ThreadFactory; 8 | 9 | /* 10 | * As using Executors you cannot manipulate the thread object directly, it's needed to create an 11 | * instance of ThreadFactory to intercept the creation of the Thread and set the 12 | * UncaughtExceptionHandler directly to the Thread instance. 13 | */ 14 | 15 | public class HandlingExceptionsInExecutors { 16 | 17 | public static void main(String[] args) throws InterruptedException, ExecutionException { 18 | 19 | System.out.println("Thread main started"); 20 | 21 | ExecutorService executorService = Executors.newFixedThreadPool(5, new MyExceptionHandlerThreadFactory()); 22 | 23 | // if executorService.submit() is used instead of execute(), the Exception will rise when invoking future.get() 24 | // try { 25 | // future.get(); 26 | // } catch (ExecutionException ex) { 27 | // ex.getCause().printStackTrace(); 28 | // } 29 | executorService.execute(new MyTask()); 30 | 31 | executorService.shutdown(); 32 | 33 | System.out.println("Thread main finished"); 34 | } 35 | } 36 | 37 | class MyTask implements Runnable { 38 | 39 | public void run() { 40 | throw new RuntimeException(); 41 | } 42 | } 43 | 44 | class MyExceptionHandler implements UncaughtExceptionHandler { 45 | 46 | public void uncaughtException(Thread t, Throwable e) { 47 | System.out.println("Exception occoured in thread " + t.getName()); 48 | } 49 | } 50 | 51 | class MyExceptionHandlerThreadFactory implements ThreadFactory { 52 | 53 | public Thread newThread(Runnable r) { 54 | Thread myThread = new Thread(r); 55 | myThread.setUncaughtExceptionHandler(new MyExceptionHandler()); 56 | return myThread; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/threads/example24/SchedulingTasksWithScheduledThreadPool.java: -------------------------------------------------------------------------------- 1 | package threads.example24; 2 | 3 | import java.util.Date; 4 | import java.util.concurrent.CountDownLatch; 5 | import java.util.concurrent.Executors; 6 | import java.util.concurrent.ScheduledExecutorService; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | /* 10 | * Schedules a Runnable task using a ScheduledExecutorService.schedule() 11 | * 12 | * It's also possible to use scheduleAtFixedRate or scheduleAtFixedDelay to run the task repeatedly 13 | * using the thread pool 14 | * 15 | * Also, blocks the main thread until the countdown reaches 0, that is, the task is done 16 | * See the previous examples to learn the CountDownLatch 17 | */ 18 | 19 | public class SchedulingTasksWithScheduledThreadPool { 20 | 21 | public static void main(String[] args) throws InterruptedException { 22 | System.out.println("Thread main started"); 23 | CountDownLatch countDownLatch = new CountDownLatch(1); 24 | 25 | ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5); 26 | 27 | System.out.println("Scheduling task to run after 5 seconds... " + new Date()); 28 | scheduledExecutorService.schedule(new MyTask(countDownLatch), 5, TimeUnit.SECONDS); 29 | scheduledExecutorService.schedule(new MyTask(countDownLatch), 5, TimeUnit.SECONDS); 30 | scheduledExecutorService.schedule(new MyTask(countDownLatch), 5, TimeUnit.SECONDS); 31 | scheduledExecutorService.schedule(new MyTask(countDownLatch), 5, TimeUnit.SECONDS); 32 | scheduledExecutorService.schedule(new MyTask(countDownLatch), 5, TimeUnit.SECONDS); 33 | 34 | countDownLatch.await(); 35 | 36 | scheduledExecutorService.shutdown(); 37 | System.out.println("Thread main finished"); 38 | } 39 | } 40 | 41 | class MyTask implements Runnable { 42 | 43 | private CountDownLatch countDownLatch; 44 | 45 | public MyTask(CountDownLatch countDownLatch) { 46 | this.countDownLatch = countDownLatch; 47 | } 48 | 49 | public void run() { 50 | System.out.println("Executing the task at: " + new Date()); 51 | countDownLatch.countDown(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/threads/example17/TerminateAllTasksInExecutorService.java: -------------------------------------------------------------------------------- 1 | package threads.example17; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.Callable; 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | 8 | /* 9 | * Terminates all tasks assigned to ExecutorService by using ExecutorService.shutdownNow() method 10 | * This method terminates immediately the running tasks and retrieves the list of tasks that hasn't 11 | * started yet 12 | * 13 | * As in this example the thread pool has size 5 and 8 tasks where assigned, then it must return 3 14 | * tasks that were queued 15 | */ 16 | 17 | public class TerminateAllTasksInExecutorService { 18 | 19 | public static void main(String[] args) throws InterruptedException { 20 | 21 | System.out.println("Thread main started"); 22 | 23 | ExecutorService executorService = Executors.newFixedThreadPool(5); 24 | executorService.submit(new SumFirstNumbers(400000)); 25 | executorService.submit(new SumFirstNumbers(300000)); 26 | executorService.submit(new SumFirstNumbers(200000)); 27 | executorService.submit(new SumFirstNumbers(100000)); 28 | executorService.submit(new SumFirstNumbers(100000)); 29 | executorService.submit(new SumFirstNumbers(100000)); 30 | executorService.submit(new SumFirstNumbers(100000)); 31 | executorService.submit(new SumFirstNumbers(100000)); 32 | 33 | Thread.sleep(1000l); 34 | 35 | List queudTasks = executorService.shutdownNow(); 36 | 37 | System.out.println("Tasks that hasn't started: " + queudTasks.size()); 38 | System.out.println("Thread main finished"); 39 | } 40 | } 41 | 42 | class SumFirstNumbers implements Callable { 43 | private int n; 44 | 45 | public SumFirstNumbers(int n) { 46 | this.n = n; 47 | } 48 | 49 | public Integer call() { 50 | int sum = 0; 51 | for (int i = 1; i <= n; i++) { 52 | try { 53 | System.out.println("[" + Thread.currentThread().getName() + "] Adding " + i); 54 | sum += i; 55 | Thread.sleep(100l); 56 | } catch (InterruptedException e) { 57 | System.out.println("Interrupting the thread while it was sleeping..."); 58 | break; 59 | } 60 | } 61 | return sum; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/threads/example8/NamingThreadUsingExecutors.java: -------------------------------------------------------------------------------- 1 | package threads.example8; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.concurrent.Callable; 6 | import java.util.concurrent.ExecutionException; 7 | import java.util.concurrent.ExecutorService; 8 | import java.util.concurrent.Executors; 9 | import java.util.concurrent.Future; 10 | import java.util.concurrent.ThreadFactory; 11 | 12 | /* 13 | * The same as example7, except that here the threads are named 14 | * in the thread pool implementing ThreadFactory interface 15 | * 16 | * The same procedure can be done to instantiate Deamon Threads 17 | * that is, threads that executes while user threads exists 18 | */ 19 | 20 | public class NamingThreadUsingExecutors { 21 | 22 | public static void main(String[] args) throws InterruptedException, ExecutionException { 23 | 24 | System.out.println("Thread main started"); 25 | 26 | ExecutorService executorService = Executors.newFixedThreadPool(5, new NamedThreadFactory()); 27 | List> returnedValues = executorService.invokeAll(Arrays.asList( 28 | new SumFirstNumbers(50), 29 | new SumFirstNumbers(40), 30 | new SumFirstNumbers(30), 31 | new SumFirstNumbers(20), 32 | new SumFirstNumbers(10))); 33 | 34 | for (Future value : returnedValues) { 35 | System.out.println(value.get()); 36 | } 37 | 38 | executorService.shutdown(); 39 | 40 | System.out.println("Thread main finished"); 41 | } 42 | } 43 | 44 | class SumFirstNumbers implements Callable { 45 | private int n; 46 | 47 | 48 | public SumFirstNumbers(int n) { 49 | this.n = n; 50 | } 51 | 52 | public Integer call() { 53 | int sum = 0; 54 | for (int i = 1; i <= n; i++) { 55 | System.out.println("[" + Thread.currentThread().getName() + "] Adding " + i); 56 | sum += i; 57 | try { 58 | Thread.sleep(200); 59 | } catch (InterruptedException e) { 60 | e.printStackTrace(); 61 | } 62 | } 63 | return sum; 64 | } 65 | } 66 | 67 | class NamedThreadFactory implements ThreadFactory { 68 | private String threadName="xuxa-thread-"; 69 | private static int count = 0; 70 | 71 | public Thread newThread(Runnable r) { 72 | Thread t = new Thread(r); 73 | t.setName(threadName + count++); 74 | return t; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/threads/example14/TerminateTaskUsingFlagExecutors.java: -------------------------------------------------------------------------------- 1 | package threads.example14; 2 | 3 | import java.util.concurrent.Callable; 4 | import java.util.concurrent.ExecutionException; 5 | import java.util.concurrent.Executors; 6 | import java.util.concurrent.Future; 7 | import java.util.concurrent.ThreadPoolExecutor; 8 | 9 | /* 10 | * Terminates a TASK by using a flag inside it. 11 | * Note that the task will not terminate immediately (that's why we put main to sleep for a while) 12 | * Comment the cancel() invocation to see the task finishing its job. 13 | * 14 | * Here, after the task is cancelled, the thread is again available in the thread pool. 15 | * When using the Thread API, when the task is cancelled the thread dies as well 16 | */ 17 | 18 | public class TerminateTaskUsingFlagExecutors { 19 | 20 | public static void main(String[] args) throws InterruptedException, ExecutionException { 21 | 22 | System.out.println("Thread main started"); 23 | 24 | ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor)Executors.newFixedThreadPool(5); 25 | 26 | SumFirstNumbers sumTask = new SumFirstNumbers(50); 27 | Future result = threadPoolExecutor.submit(sumTask); 28 | 29 | System.out.println("Number of active Threads in the pool: " + threadPoolExecutor.getActiveCount()); 30 | 31 | sumTask.cancel(); 32 | 33 | Thread.sleep(500l); 34 | 35 | System.out.println("Number of active Threads in the pool: " + threadPoolExecutor.getActiveCount()); 36 | System.out.println("Result: " + result.get()); 37 | 38 | threadPoolExecutor.shutdown(); 39 | 40 | System.out.println("Thread main finished"); 41 | } 42 | } 43 | 44 | class SumFirstNumbers implements Callable { 45 | private int n; 46 | private volatile boolean cancelTask; 47 | 48 | 49 | public SumFirstNumbers(int n) { 50 | this.n = n; 51 | this.cancelTask = false; 52 | } 53 | 54 | public Integer call() { 55 | int sum = 0; 56 | for (int i = 1; i <= n; i++) { 57 | System.out.println("[" + Thread.currentThread().getName() + "] Adding " + i); 58 | sum += i; 59 | try { 60 | Thread.sleep(200); 61 | } catch (InterruptedException e) { 62 | e.printStackTrace(); 63 | } 64 | 65 | synchronized (this) { 66 | if (cancelTask) { 67 | return -1; 68 | } 69 | } 70 | } 71 | return sum; 72 | } 73 | 74 | public void cancel() { 75 | synchronized (this) { 76 | this.cancelTask = true; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/threads/example20/WatingForThreadsToFinishUsingJoin.java: -------------------------------------------------------------------------------- 1 | package threads.example20; 2 | 3 | /* 4 | * Like the wait() / notify() strategy used in one of the previous examples, join() allows 5 | * the caller thread to wait until the target thread finishes. 6 | * 7 | * If the target thread is already done, join() returns immediately to the caller thread 8 | * (that's what happens with thread4 in this example). 9 | */ 10 | 11 | public class WatingForThreadsToFinishUsingJoin { 12 | 13 | public static void main(String[] args) throws InterruptedException { 14 | System.out.println("Thread main started"); 15 | 16 | Thread thread1 = new Thread(new MyTask(100l)); 17 | Thread thread2 = new Thread(new MyTask(200l)); 18 | Thread thread3 = new Thread(new MyTask(300l)); 19 | Thread thread4 = new Thread(new MyTask(50l)); 20 | thread1.setName("thread-1"); 21 | thread2.setName("thread-2"); 22 | thread3.setName("thread-3"); 23 | thread4.setName("thread-4"); 24 | thread1.start(); 25 | thread2.start(); 26 | thread3.start(); 27 | thread4.start(); 28 | 29 | System.out.println("[" + Thread.currentThread().getName() + "] waiting for " + thread1.getName()); 30 | thread1.join(); 31 | System.out.println(thread1.getName() + " finished!"); 32 | 33 | System.out.println("[" + Thread.currentThread().getName() + "] waiting for " + thread2.getName()); 34 | thread2.join(); 35 | System.out.println(thread2.getName() + " finished!"); 36 | 37 | System.out.println("[" + Thread.currentThread().getName() + "] waiting for " + thread3.getName()); 38 | thread3.join(); 39 | System.out.println(thread3.getName() + " finished!"); 40 | 41 | // As thread-4 already finished (smaller sleep time), the join call only immediately 42 | // returns the control to the caller thread 43 | System.out.println("[" + Thread.currentThread().getName() + "] waiting for " + thread4.getName()); 44 | thread4.join(); 45 | System.out.println(thread4.getName() + " finished!"); 46 | 47 | System.out.println("Thread main finished"); 48 | } 49 | } 50 | 51 | class MyTask implements Runnable { 52 | private long sleep; 53 | 54 | public MyTask(long sleep) { 55 | this.sleep = sleep; 56 | } 57 | 58 | public void run() { 59 | for (int i = 0; i < 10; i++) { 60 | System.out.println("[" + Thread.currentThread().getName() + "] Message " + i); 61 | try { 62 | Thread.sleep(sleep); 63 | } catch (InterruptedException e) { 64 | e.printStackTrace(); 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/threads/example22/WatingTasksToFinishesAndGettingResultsUsingExecutors.java: -------------------------------------------------------------------------------- 1 | package threads.example22; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | import java.util.concurrent.Callable; 6 | import java.util.concurrent.CountDownLatch; 7 | import java.util.concurrent.ExecutionException; 8 | import java.util.concurrent.ExecutorService; 9 | import java.util.concurrent.Executors; 10 | import java.util.concurrent.Future; 11 | 12 | /* 13 | * When dealing with Executors you do not have the thread reference, so invoking join() isn't the way. 14 | * To lock the caller thread, one strategy is to use the CountDownLatch, in which each task will 15 | * decrement the countdown when it finishes its job and the caller thread (main, in this case) 16 | * will be unlocked when the counter reaches zero. The main thread will be blocked in the method 17 | * countDownLatch.await() 18 | */ 19 | 20 | public class WatingTasksToFinishesAndGettingResultsUsingExecutors { 21 | 22 | public static void main(String[] args) throws InterruptedException, ExecutionException { 23 | System.out.println("Thread main started"); 24 | 25 | CountDownLatch countDownLatch = new CountDownLatch(4); 26 | 27 | MyTask task1 = new MyTask(500l, countDownLatch); 28 | MyTask task2 = new MyTask(1000l, countDownLatch); 29 | MyTask task3 = new MyTask(2000l, countDownLatch); 30 | MyTask task4 = new MyTask(50l, countDownLatch); 31 | 32 | ExecutorService executorService = Executors.newFixedThreadPool(4); 33 | 34 | List> resultList = executorService.invokeAll(Arrays.asList(task1, task2, task3, task4)); 35 | 36 | System.out.println("Locking main thread..."); 37 | countDownLatch.await(); 38 | System.out.println("Unlocking main thread..."); 39 | 40 | // Now the main thread can proceed as the 4 threads finished their jobs (the countdown reached 0) 41 | // They are now available in the thread pool 42 | for (int i=0; i<4; i++) { 43 | System.out.println("Task" + i + " result: " + resultList.get(i).get()); 44 | } 45 | 46 | executorService.shutdown(); 47 | 48 | System.out.println("Thread main finished"); 49 | } 50 | } 51 | 52 | class MyTask implements Callable { 53 | private long sleep; 54 | private CountDownLatch countDownLatch; 55 | 56 | public MyTask(long sleep, CountDownLatch countDownLatch) { 57 | this.sleep = sleep; 58 | this.countDownLatch = countDownLatch; 59 | } 60 | 61 | public Integer call() { 62 | int sum=0; 63 | for (int i = 1; i <= 10; i++) { 64 | System.out.println("[" + Thread.currentThread().getName() + "] Adding " + i); 65 | sum += i; 66 | try { 67 | Thread.sleep(sleep); 68 | } catch (InterruptedException e) { 69 | e.printStackTrace(); 70 | } 71 | } 72 | 73 | if (countDownLatch != null) { 74 | System.out.println(Thread.currentThread().getName() + " counting down!"); 75 | countDownLatch.countDown(); 76 | } 77 | return sum; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/threads/example21/GetResultFromTaskUsingJoinsThreadAPI.java: -------------------------------------------------------------------------------- 1 | package threads.example21; 2 | 3 | /* 4 | * Like the wait() / notify() strategy used in one of the previous examples, join() allows 5 | * the caller thread to wait until the target thread finishes. 6 | * If the target thread is already done, join() returns immediately to the caller thread 7 | * (that's what happens with thread4 in this example). 8 | * 9 | * Here, when the target thread finishes the sum, the caller thread (main) wakes up and 10 | * calls the task.getSum() method which will certainly contains the total sum as the 11 | * target thread has already finished its job. 12 | * 13 | * The task4 has a small sleep time and therefore it finishes the sum before the others. 14 | * Hence, the main thread calls the thread4.join() but immediately returns to its execution 15 | * as the thread4 is finished. 16 | */ 17 | 18 | public class GetResultFromTaskUsingJoinsThreadAPI { 19 | 20 | public static void main(String[] args) throws InterruptedException { 21 | System.out.println("Thread main started"); 22 | 23 | MyTask task1 = new MyTask(500l); 24 | MyTask task2 = new MyTask(1000l); 25 | MyTask task3 = new MyTask(2000l); 26 | MyTask task4 = new MyTask(50l); 27 | Thread thread1 = new Thread(task1); 28 | Thread thread2 = new Thread(task2); 29 | Thread thread3 = new Thread(task3); 30 | Thread thread4 = new Thread(task4); 31 | thread1.setName("thread-1"); 32 | thread2.setName("thread-2"); 33 | thread3.setName("thread-3"); 34 | thread4.setName("thread-4"); 35 | thread1.start(); 36 | thread2.start(); 37 | thread3.start(); 38 | thread4.start(); 39 | 40 | System.out.println("[" + Thread.currentThread().getName() + "] waiting for " + thread1.getName()); 41 | thread1.join(); 42 | System.out.println(thread1.getName() + " finished! Result: " + task1.getSum()); 43 | 44 | System.out.println("[" + Thread.currentThread().getName() + "] waiting for " + thread2.getName()); 45 | thread2.join(); 46 | System.out.println(thread2.getName() + " finished! Result: " + task2.getSum()); 47 | 48 | System.out.println("[" + Thread.currentThread().getName() + "] waiting for " + thread3.getName()); 49 | thread3.join(); 50 | System.out.println(thread3.getName() + " finished! Result: " + task3.getSum()); 51 | 52 | // As thread-4 already finished (smaller sleep time), the join call only immediately 53 | // returns the control to the caller thread 54 | System.out.println("[" + Thread.currentThread().getName() + "] waiting for " + thread4.getName()); 55 | thread4.join(); 56 | System.out.println(thread4.getName() + " finished! Result: " + task4.getSum()); 57 | 58 | System.out.println("Thread main finished"); 59 | } 60 | } 61 | 62 | class MyTask implements Runnable { 63 | private long sleep; 64 | private int sum; 65 | 66 | public MyTask(long sleep) { 67 | this.sleep = sleep; 68 | } 69 | 70 | public void run() { 71 | for (int i = 1; i <= 10; i++) { 72 | System.out.println("[" + Thread.currentThread().getName() + "] Adding " + i); 73 | sum += i; 74 | try { 75 | Thread.sleep(sleep); 76 | } catch (InterruptedException e) { 77 | e.printStackTrace(); 78 | } 79 | } 80 | } 81 | 82 | public int getSum() { 83 | return this.sum; 84 | } 85 | } 86 | --------------------------------------------------------------------------------