Core Java

Java Concurrency: Threads and Runnables

Threads are everywhere, they are the basic building block of every server application out there.

Usually in Java using threads is just a combination of Executors and Runnables however let’s have a closer look on a thread and how it works.

Supposing I want to start a thread, it can be as simple as this.

Thread thread = new Thread(() {
            System.out.println("Running somewhere else");

What will happen in this case is that we create a thread and we join the thread until the operation finishes.

If we check the internals of the thread class we can see that in our initialization we passed a Runnable.

So the Runnable essentially instructs the thread what to do. It encapsulates the logic that will be executed once we start a thread.
If we check the source code the Runnable we can see that it is an interface with only one function.

public interface Runnable {
    public abstract void run();

Essentially Runnable is a functional interface.

From the documentation.

This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

The runnable can be passed to lambdas, Executors-Thread pools and use it to create standalone threads.

So let’s have a closer look on what a thread does.

If we check the implementation we can see that a Thread implements the Runnable interface.

public class Thread implements Runnable {
    public Thread(Runnable target) {
        this(null, target, "Thread-" + nextThreadNum(), 0);

We also displayed a specific thread constructor on purpose, the constructor passes the runnable as a target variable.

If we check the run method of the thread it will execute the Runnable we passed previously.

    public void run() {
        if (target != null) {

Supposing no runnable has been passed in one of the constructors the thread will not execute anything.
So let’s see another approach where we shall run a thread by extending it.

public class CustomThread extends Thread {

    public void run() {
        System.out.println("No runnable passed");


Which we can run like this

Thread thread = new CustomThread();

So start will essentially execute the run the method that we implemented or the original run method using the target Runnable.
If we check start we shall stumble upon the following code block

        boolean started = false;
        try {
            started = true;
        } finally {
            try {
                if (!started) {
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */

As we see there a method called start0() is invoked.
This method is essentially

private native void start0();

We can see the native methods on the  Thread.c class.

static JNINativeMethod methods[] = {
    {"start0",           "()V",        (void *)&JVM_StartThread},
    {"setNativeName",    "(" STR ")V", (void *)&JVM_SetNativeThreadName},

This brings us to the actual native code starting the thread which will end up on the actual implementation based on the os used.
For example on linux it would be pthreads.

Published on Java Code Geeks with permission by Emmanouil Gkatziouras, partner at our JCG program. See the original article here: Java Concurrency: Threads and Runnables

Opinions expressed by Java Code Geeks contributors are their own.

Emmanouil Gkatziouras

He is a versatile software engineer with experience in a wide variety of applications/services.He is enthusiastic about new projects, embracing new technologies, and getting to know people in the field of software.
Notify of

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Inline Feedbacks
View all comments
Back to top button