The main thread is a starting place from which you may spawn new threads to perform your own tasks. To do that you need to write code has to be executed in a separated thread and then start it.
Create custom threads
Java primarily has two ways to create a new thread that performs a task you need.
- by extending the
Threadclass and overriding itsrunmethod
class HelloThread extends Thread {
@Override
public void run() {
String helloMsg = String.format("Hello, i'm %s", getName());
System.out.println(helloMsg);
}
}- by implementing the
Runnableinterface and passing the implementation to the constructor of theThreadclass
class HelloRunnable implements Runnable {
@Override
public void run() {
String threadName = Thread.currentThread().getName();
String helloMsg = String.format("Hello, i'm %s", threadName);
System.out.println(String.format();
}
}In both cases, you should override the
run method that is a regular Java method and contain code to perform a task. But what approach is better? It depends on your preferences and the task. If you extend the Thread class, you can accept fields and methods of the base class, but then you cannot extend other classes because Java doesn't have multiple-inheritance of classes.Here are two objects obtained in accordance with the approaches described above.
Thread t1 = new HelloThread(); // a subclass of Thread
Thread t2 = new Thread(new HelloRunnable()); // passing runnableIt is also possible to specify a name to your thread passing it to the constructor:
Thread myThread = new Thread(new HelloRunnable(), "my-thread");If you are already familiar with lambda expressions, you may just write:
Thread t3 = new Thread(() -> {
System.out.println(String.format("Hello, i'm %s", Thread.currentThread().getName()));
});After you have created objects for threads, the threads are not started yet. You should start them to perform tasks you need.
Starting threads
To start a thread, the class
Thread has a method called start(). After you invoke this method, sometime later, the method run will be invoked automatically after some time, but not immediately.Suppose, inside the main method you create an object of
HelloThread named t and start it.Thread helloThread = new HelloThread(); // an object representing a thread
helloThread.start();After some time, it prints something like:
Hello, i'm Thread-0Below is a picture that explains how a thread actually starts.
As you may see, there is some delay between starting a thread and it really starts works (run).
By default, a new thread is running in non-daemon mode. Remember, the difference between the daemon and the non-daemon mode is in that JVM will terminate the running program as soon as there are no more non-daemon threads left.
Important 1: do not confuse methods
run and start. You must invoke start if you'd like to execute your inside run in another thread. If you invoke run diretly, the code will be executed in the same thread.Important 2: if you try to start a thread more than once, the
start throws IllegalThreadStateException.Despite the fact that within a single thread all statements are executed sequentially, it is impossible to determine the relative order of statements between multiple threads without additional measures that we will not consider in this lesson.
public class StartingMultipleThreads {
public static void main(String[] args) {
Thread t1 = new HelloThread();
Thread t2 = new HelloThread();
t1.start();
t2.start();
System.out.println("Finished");
}
}The order of displaying messages can be any. Here is one of them:
Hello, i'm Thread-1
Finished
Hello, i'm Thread-0Alternatively, all threads may print their text after the main thread prints "Finished":
Finished
Hello, i'm Thread-0
Hello, i'm Thread-1So, even though we call the
start method sequentially for each thread, we do not know when the run method will be really called.Important 3: do not rely on the order of execution of statements between different threads, unless you take special measures.
A simple multithreaded program
Let's consider a simple multithreaded program with two threads. The first thread reads numbers from the standard input and prints their squares. At the same time, the main thread periodically prints messages to the standard output. Both threads work simultaneously.
Here is a thread that reads numbers in a loop and squares them. It has a break statement to stop the loop if the given number is 0.
class SquareWorkerThread extends Thread {
private final Scanner scanner = new Scanner(System.in);
public SquareWorkerThread(String name) {
super(name);
}
@Override
public void run() {
while (true) {
int number = scanner.nextInt();
if (number == 0) {
break;
}
System.out.println(number * number);
}
System.out.println(String.format("%s finished", getName()));
}
}Inside the
main method, the program starts an object of SquareWorkerThread class and then writes messages to the standard output from the main thread.public class SimpleMultithreadedProgram {
public static void main(String[] args) {
Thread worker = new SquareWorkerThread("square-worker");
worker.start(); // start a worker (not run!)
for (long i = 0; i < 5_555_555_543L; i++) {
if (i % 1_000_000_000 == 0) {
System.out.println("Hello from the main!");
}
}
}
}Here is an example of inputs and outputs with comments:
Hello from the main! // the program outputs it
2 // the program reads it
4 // the program outputs it
Hello from the main! // the program outputs it
3 // the program reads it
9 // the program outputs it
5 // the program reads it
Hello from the main! // the program outputs it
25 // the program outputs it
0 // the program reads it
square-worker finished // the program outputs it
Hello from the main! // the program outputs it
Hello from the main! // the program outputs it
Process finished with exit code 0As you can see, this program performs two tasks "at the same time": one in the main thread and another one in the worker thread. Actually, it may be not "the same time" in the physical sense, but both tasks are given some time to be executed.