Java Multithreading Programming Tutorial with Examples
2. Example start with Thread
We need 2 class participated in this example.
- HelloMain is a class with the main method, it is a main thread.
- HelloThread is a class extends the Thread class. It was created and is enabled to run within the main stream and will run parallel to the main thread.
package org.o7planning.tutorial.thread.hellothread;
public class HelloMain {
public static void main(String[] args) throws InterruptedException {
int idx = 1;
for (int i = 0; i < 2; i++) {
System.out.println("Main thread running " + idx++);
// Sleep 2101 miliseconds.
Thread.sleep(2101);
}
HelloThread helloThread = new HelloThread();
// Run thread
helloThread.start();
for (int i = 0; i < 3; i++) {
System.out.println("Main thread running " + idx++);
// Sleep 2101 miliseconds.
Thread.sleep(2101);
}
System.out.println("==> Main thread stopped");
}
}
HelloThread.java
package org.o7planning.tutorial.thread.hellothread;
public class HelloThread extends Thread {
// Code of method run() will be executed when
// thread call start()
@Override
public void run() {
int index = 1;
for (int i = 0; i < 10; i++) {
System.out.println(" - HelloThread running " + index++);
try {
// Sleep 1030 miliseconds.
Thread.sleep(1030);
} catch (InterruptedException e) {
}
}
System.out.println(" - ==> HelloThread stopped");
}
}
Results of running class HelloMain
3. Runnable Interface
You can also create a thread from one class to implements Runnable interface. See examples:
RunnableDemo.java
package org.o7planning.tutorial.thread.runnable;
public class RunnableDemo implements Runnable {
@Override
public void run() {
int idx = 1;
for (int i = 0; i < 5; i++) {
System.out.println("Hello from RunnableDemo " + idx++);
// Sleep 2 second.
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
}
}
RunnableTest.java
package org.o7planning.tutorial.thread.runnable;
public class RunnableTest {
public static void main(String[] args) throws InterruptedException {
System.out.println("Main thread running..");
// Create a thread from Runnable.
Thread thread = new Thread(new RunnableDemo());
thread.start();
// Sleep 5 seconds.
Thread.sleep(5000);
System.out.println("Main thread stopped");
}
}
Run class RunnableTest:
Main thread running..
Hello from RunnableDemo 1
Hello from RunnableDemo 2
Hello from RunnableDemo 3
Main thread stopped
Hello from RunnableDemo 4
Hello from RunnableDemo 5
4. Deamon Thread
Java divides Thread into 2 types: normal thread and Deamon Thread. The difference is the way of ending. In a program, normal threads and Deamon thread run parallel each other. When all normal thread finish, all Deamon threads will be ending.
Note:
Use setDeamon(boolean) to set up a thread that can be Deamon or not. Noticeably, you only can call setDeamon(boolean) when the thread has not ran already. It means that when thread has ran you cannot change the thread from non-deamon to deamon and vice versa.
When a new thread is created, it inherits the deamon feature from its father thread. Thus, when you create a thread in main method of a class, that thread naturally is non-deamon, so thread created by default is also non-deamon. Therefore, if you create a new thread in a Deamon thread, by default it also
Thread thread = new MyThread();
// marks this thread as a daemon thread
// This method is only called when the thread is not a start.
// In the case of start, it will be throws an exception.
thread.setDeamon(true);
// marks this thread as a none-daemon thread
// This method is only called when the thread is not a start.
// In the case of start, it will be throws an exception.
thread.setDeamon(false);
For ease of understanding we consider the following example. We have three classes involved in the example:
NoneDeamonThread.java
package org.o7planning.tutorial.thread.deamon;
public class NoneDeamonThread extends Thread {
@Override
public void run() {
int i = 0;
// Loop 10 times. This thread will end.
while (i < 10) {
System.out.println(" - Hello from None Deamon Thread " + i++);
try {
// Sleep 1 second
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
// None deamon thread ending.
System.out.println("\n==> None Deamon Thread ending\n");
}
}
DeamonThread.java
package org.o7planning.tutorial.thread.deamon;
class DeamonThread extends Thread {
@Override
public void run() {
int count = 0;
// Infinite loop
while (true) {
System.out.println("+ Hello from Deamon Thread " + count++);
try {
// Sleep 2 second
sleep(2000);
} catch (InterruptedException e) {
}
}
}
}
DaemonTest.java
package org.o7planning.tutorial.thread.deamon;
public class DaemonTest {
public static void main(String[] args) {
System.out.println("==> Main Thread running..\n");
// Create thread
Thread deamonThread = new DeamonThread();
// Set deamon true
deamonThread.setDaemon(true);
deamonThread.start();
// Create other thread
new NoneDeamonThread().start();
try {
// Sleep 5 second
Thread.sleep(5000);
} catch (InterruptedException e) {
}
// Main Thread ending
System.out.println("\n==> Main Thread ending\n");
}
}
Results of running DeamonTest:
The above illustration shows that Deamon thread has been stopped when all of the normal threads stop although its code is infinite.
What is Deamon thread used for?
One of the important Deamon threads of Java is Garbage Collection Thread. It means to collect disused resources to liberate the memory. When all user's threads stop operating, Garbage Collection Thread also stop.
5. Using join() & join(long)
Thread.join() is a method notifying that please wait for this thread to be completed before the parent thread continues to run.
// Parent thread must wait until the end of this thread, before being continued.
// (This is equivalent to calling join(0))
public final void join() throws InterruptedException;
// Parent thread must wait 'millis' milliseconds to continue running.
// After call join(long).
// If the parameter millis = 0 means to wait until the end of this thread.
public final synchronized void join(long millis) throws InterruptedException;
// Parent thread must wait 'millis' milliseconds and 'nanos' nanoseconds to continue running.
// After call join(long,int).
// 1 second = 1000000 nanoseconds.
public final synchronized void join(long millis, int nanos) throws InterruptedException;
Consider an illustration:
JoinThread.java
package org.o7planning.tutorial.thread.join;
public class JoinThread extends Thread {
private String threadName;
private int count;
public JoinThread(String threadName, int count) {
this.threadName = threadName;
this.count = count;
}
@Override
public void run() {
for (int i = 1; i < count + 1; i++) {
System.out.println("Hello from " + this.threadName + " " + i);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
System.out.println("\n==> Thread " + threadName + " end!\n");
}
}
JoinTest.java
package org.o7planning.tutorial.thread.join;
public class JoinTest {
public static void main(String[] args) throws InterruptedException {
System.out.println("\n==> Main thread starting..\n");
Thread joinThreadA = new JoinThread("A*", 2);
Thread joinThreadB = new JoinThread("B*", 3);
// None join Thread.
Thread noJoinThreadC = new JoinThread("C", 5);
joinThreadA.start();
joinThreadB.start();
noJoinThreadC.start();
// Using join()
joinThreadA.join();
joinThreadB.join();
// The following code will have to wait until 2
// JoinThread A, B completed.
System.out.println("Hello from main thread...");
System.out.println("Thread A isLive? " + joinThreadA.isAlive());
System.out.println("Thread B isLive? " + joinThreadB.isAlive());
System.out.println("Thread C isLive? " + noJoinThreadC.isAlive());
System.out.println("\n==> Main Thread end!\n");
}
}
The result of running JoinTest:
==> Main thread starting..
Hello from A* 1
Hello from C 1
Hello from B* 1
Hello from A* 2
Hello from C 2
Hello from B* 2
==> Thread A* end!
Hello from B* 3
Hello from C 3
==> Thread B* end!
Hello from C 4
Hello from main thread...
Thread A isLive? false
Thread B isLive? false
Thread C isLive? true
==> Main Thread end!
Hello from C 5
==> Thread C end!
Example of using join(long millis):
JoinTest2.java
package org.o7planning.tutorial.thread.join;
public class JoinTest2 {
public static void main(String[] args) throws InterruptedException {
System.out.println("\n==> Main thread starting..\n");
Thread joinThreadA = new JoinThread("A*", 5);
joinThreadA.start();
// Main thread must wait to 5000 miliseconds,
// and then continue running. (Not necessarily joinThreadA finish)
joinThreadA.join(5000);
System.out.println("Main thread after 5000 milli second");
System.out.println("Hello from main thread...");
System.out.println("Thread A isLive? " + joinThreadA.isAlive());
System.out.println("\n==> Main Thread end!\n");
}
}
Results of running the example:
==> Main thread starting..
Hello from A* 1
Hello from A* 2
Hello from A* 3
Main thread after 5000 milli second
Hello from main thread...
Thread A isLive? true
==> Main Thread end!
Hello from A* 4
Hello from A* 5
==> Thread A* end!
6. Handling exception in thread
The Thread.setDefaultUncaughtExceptionHandler() method set the default handler invoked when a thread abruptly terminates due to an uncaught exception, and no other handler has been defined for that thread.
ThreadExceptionDemo.java
package org.o7planning.tutorial.thread.exception;
import java.util.Random;
public class ThreadExceptionDemo {
public static class RunnableTest implements Runnable {
@Override
public void run() {
System.out.println("Thread running ..");
while (true) {
Random r = new Random();
// A random number from 0-99
int i = r.nextInt(100);
System.out.println("Next value " + i);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
if (i > 70) {
// Simulate an exception was not handled in the thread.
throw new RuntimeException("Have a problem...");
}
}
}
}
public static void main(String[] args) {
System.out.println("==> Main thread running...");
Thread thread = new Thread(new RunnableTest());
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("#Thread: " + t);
System.out.println("#Thread exception message: " + e.getMessage());
}
});
thread.start();
System.out.println("==> Main thread end...");
}
}
Results of running the example:
==> Main thread running...
==> Main thread end...
Thread running ..
Next value 21
Next value 42
Next value 67
Next value 18
Next value 34
Next value 40
Next value 11
Next value 1
Next value 92
#Thread: Thread[Thread-0,5,main]
#Thread exception message: Have a problem...
7. Using yield()
Theoretically, to ‘yield’ means to let go, to give up, to surrender. A yielding thread tells the virtual machine that it’s willing to let other threads be scheduled in its place. This indicates that it’s not doing something too critical. Note that it’s only a hint, though, and not guaranteed to have any effect at all.
yield() is defined as following in Thread.java
public static native void yield();
so, yield() method is used when you see that thread is free, it's not doing anything important, it suggests operating system give priority temporarily to the other thread.
The example below, there are two threads, each thread print out a text 100K times (the numbers are large enough to see the difference). One thread is the highest priority, and other thread is lowest priority. See completion time of 2 threads.
YieldThreadExample.java
package org.o7planning.tutorial.thread.yield;
import java.util.Date;
public class YieldThreadExample {
private static Date importantEndTime;
private static Date unImportantEndTime;
public static void main(String[] args) {
importantEndTime = new Date();
unImportantEndTime = new Date();
System.out.println("Create thread 1");
Thread importantThread = new ImportantThread();
// Set the highest priority for this thread.
importantThread.setPriority(Thread.MAX_PRIORITY);
System.out.println("Create thread 2");
Thread unImportantThread = new UnImportantThread();
// Set the lowest priority for this thread.
unImportantThread.setPriority(Thread.MIN_PRIORITY);
// Start threads.
unImportantThread.start();
importantThread.start();
}
// A important job which requires high priority.
static class ImportantThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
System.out.println("\n Important work " + i);
// Notifying the operating system,
// this thread gives priority to other threads.
Thread.yield();
}
// The end time of this thread.
importantEndTime = new Date();
printTime();
}
}
static class UnImportantThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
System.out.println("\n -- UnImportant work " + i);
}
// The end time of this thread.
unImportantEndTime = new Date();
printTime();
}
}
private static void printTime() {
// Interval (Milliseconds)
long interval = unImportantEndTime.getTime() - importantEndTime.getTime();
System.out.println("UnImportant Thread - Important Thread = " //
+ interval + " milliseconds");
}
}
The result: the lower priority thread has completed the task 51 milliseconds faster than the thread with higher priority.
...
Important work 99995
Important work 99996
Important work 99997
Important work 99998
Important work 99999
UnImportant Thread - Important Thread = -269 milliseconds
Java Basic
- Customize java compiler processing your Annotation (Annotation Processing Tool)
- Java Programming for team using Eclipse and SVN
- Java WeakReference Tutorial with Examples
- Java PhantomReference Tutorial with Examples
- Java Compression and Decompression Tutorial with Examples
- Configuring Eclipse to use the JDK instead of JRE
- Java String.format() and printf() methods
- Syntax and new features in Java 8
- Java Regular Expressions Tutorial with Examples
- Java Multithreading Programming Tutorial with Examples
- JDBC Driver Libraries for different types of database in Java
- Java JDBC Tutorial with Examples
- Get the values of the columns automatically increment when Insert a record using JDBC
- Java Stream Tutorial with Examples
- Java Functional Interface Tutorial with Examples
- Introduction to the Raspberry Pi
- Java Predicate Tutorial with Examples
- Abstract class and Interface in Java
- Access modifiers in Java
- Java Enums Tutorial with Examples
- Java Annotations Tutorial with Examples
- Comparing and Sorting in Java
- Java String, StringBuffer and StringBuilder Tutorial with Examples
- Java Exception Handling Tutorial with Examples
- Java Generics Tutorial with Examples
- Manipulating files and directories in Java
- Java BiPredicate Tutorial with Examples
- Java Consumer Tutorial with Examples
- Java BiConsumer Tutorial with Examples
- What is needed to get started with Java?
- History of Java and the difference between Oracle JDK and OpenJDK
- Install Java on Windows
- Install Java on Ubuntu
- Install OpenJDK on Ubuntu
- Install Eclipse
- Install Eclipse on Ubuntu
- Quick Learning Java for beginners
- History of bits and bytes in computer science
- Data Types in java
- Bitwise Operations
- if else statement in java
- Switch Statement in Java
- Loops in Java
- Arrays in Java
- JDK Javadoc in CHM format
- Inheritance and polymorphism in Java
- Java Function Tutorial with Examples
- Java BiFunction Tutorial with Examples
- Example of Java encoding and decoding using Apache Base64
- Java Reflection Tutorial with Examples
- Java remote method invocation - Java RMI Tutorial with Examples
- Java Socket Programming Tutorial with Examples
- Which Platform Should You Choose for Developing Java Desktop Applications?
- Java Commons IO Tutorial with Examples
- Java Commons Email Tutorial with Examples
- Java Commons Logging Tutorial with Examples
- Understanding Java System.identityHashCode, Object.hashCode and Object.equals
- Java SoftReference Tutorial with Examples
- Java Supplier Tutorial with Examples
- Java Aspect Oriented Programming with AspectJ (AOP)
Show More
- Java Servlet/Jsp Tutorials
- Java Collections Framework Tutorials
- Java API for HTML & XML
- Java IO Tutorials
- Java Date Time Tutorials
- Spring Boot Tutorials
- Maven Tutorials
- Gradle Tutorials
- Java Web Services Tutorials
- Java SWT Tutorials
- JavaFX Tutorials
- Java Oracle ADF Tutorials
- Struts2 Framework Tutorials
- Spring Cloud Tutorials