Jakob Jenkov |
AJavaThread is like a virtual CPU that can execute your Java code - inside your Java application. when a Java application is started itsmain()
method is executed by themain thread - a special thread that is created by the Java VM to run your application. From inside your application you can create and start more threads which can execute parts of your application code in parallel with the main thread.
Java threads are objects like any other Java objects. Threads are instances of classjava.lang.Thread
, or instances of subclasses of this class. In addition to being objects, java threads can also execute code. In this Java thread tutorial I will explain how to create and start threads.
In case you prefer video, here is a video version of thisJava Threads tutorial.
Creating a thread in Java is done like this:
Thread thread = new Thread();
To start the Java thread you will call its start() method, like this:
thread.start();
This example doesn't specify any code for the thread to execute. Therfore the thread will stop again right away after it is started.
There are two ways to specify what code the thread should execute. The first is to create a subclass of Thread and override therun()
method. The second method is to pass an object that implementsRunnable
(java.lang.Runnable
to theThread
constructor. Both methods are covered below.
The first way to specify what code a thread is to run, is to create a subclass of Thread and override therun()
method. Therun()
method is what is executed by the thread after you callstart()
. Here is an example of creating a JavaThread
subclass:
public class MyThread extends Thread { public void run(){ System.out.println("MyThread running"); } }
To create and start the above thread you can do like this:
MyThread myThread = new MyThread(); myTread.start();
Thestart()
call will return as soon as the thread is started. It will not wait until therun()
method is done. Therun()
method will execute as if executed by a different CPU. When therun()
method executes it will print out the text "MyThread running".
You can also create an anonymous subclass ofThread
like this:
Thread thread = new Thread(){ public void run(){ System.out.println("Thread Running"); } } thread.start();
This example will print out the text "Thread running" once therun()
method is executed by the new thread.
The second way to specify what code a thread should run is by creating a class that implements thejava.lang.Runnable
interface. A Java object that implements theRunnable
interface can be executed by a JavaThread
. How that is done is shown a bit later in this tutorial.
TheRunnable
interface is a standardJava Interface that comes with the Java platform. TheRunnable
interface only has a single methodrun()
. Here is basically how theRunnable
interface looks:
public interface Runnable() { public void run();}
Whatever the thread is supposed to do when it executes must be included in the implementation of therun()
method. There are three ways to implement theRunnable
interface:
Runnable
interface.Runnable
interface.Runnable
interface.All three options are explained in the following sections.
The first way to implement the JavaRunnable
interface is by creating your own Java class that implements theRunnable
interface. Here is an example of a custom Java class that implements theRunnable
interface:
public class MyRunnable implements Runnable { public void run(){ System.out.println("MyRunnable running"); } }
All thisRunnable
implementation does is to print out the textMyRunnable running
. After printing that text, therun()
method exits, and the thread running therun()
method will stop.
You can also create an anonymous implementation ofRunnable
. Here is an example of an anonymous Java class that implements theRunnable
interface:
Runnable myRunnable = new Runnable(){ public void run(){ System.out.println("Runnable running"); } }
Apart from being an anononymous class, this example is quite similar to the example that used a custom class to implement theRunnable
interface.
The third way to implement theRunnable
interface is by creating aJava Lambda implementation of theRunnable
interface. This is possible because theRunnable
interface only has a single unimplemented method, and is therefore practically (although possibly unintentionally) afunctional Java interface.
Here is an example of a Java lambda expression that implements theRunnable
interface:
Runnable runnable = () -> { System.out.println("Lambda Runnable running"); };
To have therun()
method executed by a thread, pass an instance of a class, anonymous class or lambda expression that implements theRunnable
interface to aThread
in its constructor. Here is how that is done:
Runnable runnable = new MyRunnable(); // or an anonymous class, or lambda...Thread thread = new Thread(runnable);thread.start();
When the thread is started it will call therun()
method of theMyRunnable
instance instead of executing it's ownrun()
method. The above example would print out the text "MyRunnable running".
There are no rules about which of the two methods that is the best. Both methods works. Personally though, I prefer implementingRunnable
, and handing an instance of the implementation to aThread
instance. When having theRunnable
's executed by athread pool it is easy to queue up theRunnable
instances until a thread from the pool is idle. This is a little harder to do withThread
subclasses.
Sometimes you may have to implementRunnable
as well as subclassThread
. For instance, if creating a subclass ofThread
that can execute more than oneRunnable
. This is typically the case when implementing a thread pool.
When creating and starting a thread a common mistake is to call therun()
method of theThread
instead ofstart()
, like this:
Thread newThread = new Thread(MyRunnable()); newThread.run(); //should be start();
At first you may not notice anything because theRunnable
'srun()
method is executed like you expected. However, it is NOT executed by the new thread you just created. Instead therun()
method is executed by the thread that created the thread. In other words, the thread that executed the above two lines of code. To have therun()
method of theMyRunnable
instance called by the new created thread,newThread
, you MUST call thenewThread.start()
method.
When you create a Java thread you can give it a name. The name can help you distinguish different threads from each other. For instance, if multiple threads write toSystem.out
it can be handy to see which thread wrote the text. Here is an example:
Thread thread = new Thread("New Thread") { public void run(){ System.out.println("run by: " + getName()); } }; thread.start(); System.out.println(thread.getName());
Notice the string "New Thread" passed as parameter to theThread
constructor. This string is the name of the thread. The name can be obtained via theThread
'sgetName()
method. You can also pass a name to aThread
when using aRunnable
implementation. Here is how that looks:
MyRunnable runnable = new MyRunnable(); Thread thread = new Thread(runnable, "New Thread"); thread.start(); System.out.println(thread.getName());
Notice however, that since theMyRunnable
class is not a subclass ofThread
, it does not have access to thegetName()
method of the thread executing it.
TheThread.currentThread()
method returns a reference to theThread
instance executingcurrentThread()
. This way you can get access to the JavaThread
object representing the thread executing a given block of code. Here is an example of how to useThread.currentThread()
:
Thread thread = Thread.currentThread();
Once you have a reference to theThread
object, you can call methods on it. For instance, you can get the name of the thread currently executing the code like this:
String threadName = Thread.currentThread().getName();
Here is a small example. First it prints out the name of the thread executing themain()
method. This thread is assigned by the JVM. Then it starts up 10 threads and give them all a number as name ("" + i
). Each thread then prints its name out, and then stops executing.
public class ThreadExample { public static void main(String[] args){ System.out.println(Thread.currentThread().getName()); for(int i=0; i<10; i++){ new Thread("" + i){ public void run(){ System.out.println("Thread: " + getName() + " running"); } }.start(); } }}
Note that even if the threads are started in sequence (1, 2, 3 etc.) they may not execute sequentially, meaning thread 1 may not be the first thread to write its name toSystem.out
. This is because the threads are in principle executing in parallel and not sequentially. The JVM and/or operating system determines the order in which the threads are executed. This order does not have to be the same order in which they were started.
A thread can pause itself by calling the static methodThread.sleep()
. Thesleep()
takes a number of milliseconds as parameter. Thesleep()
method will attempt to sleep that number of milliseconds before resuming execution. The Threadsleep()
is not 100% precise, but it is pretty good still. Here is an example of pausing a Java thread for 3 seconds (3.000 millliseconds) by calling theThread
sleep()
method:
try { Thread.sleep(10L * 1000L);} catch (InterruptedException e) { e.printStackTrace();}
The thread executing the Java code above, will sleep for approximately 10 seconds (10.000 milliseconds).
Stopping a Java Thread requires some preparation of your thread implementation code. The JavaThread
class contains astop()
method, but it is deprecated. The originalstop()
method would not provide any guarantees about in what state the thread was stopped. That means, that all Java objects the thread had access to during execution would be left in an unknown state. If other threads in your application also has access to the same objects, your application could fail unexpectedly and unpredictably.
Instead of calling thestop()
method you will have to implement your thread code so it can be stopped. Here is an example of a class that implementsRunnable
which contains an extra method calleddoStop()
which signals to theRunnable
to stop. TheRunnable
will check this signal and stop when it is ready to do so.
public class MyRunnable implements Runnable { private boolean doStop = false; public synchronized void doStop() { this.doStop = true; } private synchronized boolean keepRunning() { return this.doStop == false; } @Override public void run() { while(keepRunning()) { // keep doing what this thread should do. System.out.println("Running"); try { Thread.sleep(3L * 1000L); } catch (InterruptedException e) { e.printStackTrace(); } } }}
Notice thedoStop()
andkeepRunning()
methods. ThedoStop()
is intended to be called from another thread than the thread executing theMyRunnable
'srun()
method. ThekeepRunning()
method is called internally by the thread executing theMyRunnable
'srun()
method. As long asdoStop()
has not been called thekeepRunning()
method will returntrue
- meaning the thread executing therun()
method will keep running.
Here is an example of starting a Java thread that executes an instance of the aboveMyRunnable
class, and stopping it again after a delay:
public class MyRunnableMain { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable); thread.start(); try { Thread.sleep(10L * 1000L); } catch (InterruptedException e) { e.printStackTrace(); } myRunnable.doStop(); }}
This example first creates aMyRunnable
instance, then passes that instance to a thread and starts the thread. Then the thread executing themain()
method (the main thread) sleeps for 10 seconds, and then calls thedoStop()
method of theMyRunnable
instance. This will cause the thread executing theMyRunnable
method to stop, because thekeepRunning()
will returnfalse
afterdoStop()
has been called.
Please keep in mind that if yourRunnable
implementation needs more than just therun()
method (e.g. astop()
orpause()
method too), then you can no longer create yourRunnable
implementation with a Java lambda expression. A Java lambda can only implement a single method. Instead you must use a custom class, or a custom interface that extendsRunnable
which has the extra methods, and which is implemented by an anonymous class.
A daemon thread in Java is a thread that does not keep the Java Virtual Machine (JVM) running if the main thread exits the application. A non-daemon thread will keep the JVM running even if the main thread exits the application.
You tell a Thread to be a daemon thread via its setDaemon() method. Here is an example of creating a daemon thread in Java:
Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("Daemon Thread running."); }});thread.setDaemon(true);thread.start();try { thread.join();} catch (InterruptedException e) { throw new RuntimeException(e);}
The last call to thread.join() is done only to make sure the main application thread does not exit (and shut down the JVM) before the daemon thread has had a chance to execute.
Tweet | |
Jakob Jenkov |