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");
        });
        thread.start();
        thread.join();

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.

@FunctionalInterface
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.


...
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

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 {

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

}

Which we can run like this

        Thread thread = new CustomThread();
        thread.start();
        thread.join();

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 {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } 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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

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