Java Concurrency - The Basics
Overview of threads, and simple ways to use them
Overview
Alright concurrency confuses the hell out of me sometimes, so bear with me. This is gonna be a learning session for the both of us. I’m even gonna include drawings for maximum understanding. As always, correct me if I’m wrong at [email protected]
.
Concurrency is all about handling two or more threads in parallel. A thread
is the smallest unit of execution in a program.
Every program in Java will have at least one thread. The default thread created every time you run your program is called the main
thread. With one thread, everything runs sequentially. This is fine for a lot of programs, but you run into issues when you want two things to happen at the same time.
Example
What if you wanted to reach out to an external API, but allow the user to continue doing other things in your program? With a single thread, nothing else can happen while we wait for the request. Your user will be angry. Angry at you. Do you want people to hate you?
Instead, lets create another thread
to handle that interaction with the API. That way your main
thread can still deal with the user. When the request completes, it can give the nice API info wherever it’s needed.
I will not respond to any emails judging my handwriting
The Basics
The above example is just one way concurrency can help you write an efficient program, and we’re gonna get to that level eventually. First, let’s start with the Thread
class.
The Thread class is one tool Java gives us to create and manage a thread. It contains methods for starting and stopping a thread, as well as several setters and getters to give your thread some useful attributes (e.g., name, ID, priority)
The Thread
class implements the Runnable
functional interface. This interface has one method, run()
. When we want to use the Thread
class, we must make our own implementation of this method.
The code contained in the run()
method is the action we want the thread to take. Lets make it print something. Imagine your entire existence is dedicated to showing some text in a console. Here we go:
1
2
3
4
5
6
class Printer extends Thread {
@Override
public void run() {
System.out.println("I am the printer thread, this all I am");
}
}
In our Main
class, we instantiate our Printer
class, then call start()
on the object. This Thread
method we inherited creates a new thread, and will execute our run()
method in the new thread.
1
2
3
4
5
6
class Concurrency {
public static void main(String[] args) {
Printer p = new Printer();
p.start();
}
}
Output:
1
I am the printer thread, this all I am
Hooray. Once the thread in our example finishes all of its actions contained in the run()
method, it will automatically terminate.
Because we extended Thread
, we can directly call Thread
methods on it. But inheriting from one class prevents us from inheriting from another. So is there a better way? Yes, obviously.
The bigger brain way
Because Thread
implements Runnable
, we can make our own class that also implements the interface. The Thread
class provides us a constructor that accepts a Runnable
type object, so if we give our custom class to Thread()
, the thread object created will allow us to perform the same actions as before, but with more flexibility. Now we’re free to extend whichever parent class we want, as long as we implement Runnable
and its run()
method.
1
2
3
4
5
6
class Printer implements Runnable {
@Override
public void run() {
System.out.println("Still a printer thread, but more flexible, so I guess that's cool");
}
}
Now similar to previous main thread, we instantiate our Printer
class, and let’s set it to a Runnable
reference type so we could swap out the actual type Printer
with a different runnable later on if we wanted to. After this, we’ll make a new Thread
object, and pass our Printer
object into its constructor. Then we can call start()
on the Thread
object just like before:
1
2
3
4
5
6
7
8
9
class Concurrency {
public static void main(String[] args) {
Runnable printer = new Printer();
Thread myThread = new Thread(printer);
myThread.start();
}
}
1
Still a printer thread, but more flexible, so I guess that's cool
More to follow
This is a very basic demonstration of the Thread
class and Runnable
interface, and how implementing the latter in your own custom class can provide more flexibility than inheriting from Thread
. I plan on updating this post with more information, or creating a whole category just for concurrency. I need to better my understanding of the more advanced topics before I start yapping on here though, so I’ll work on that. Any questions, suggestions, corrections, can be sent to [email protected]
.
Sources
- https://www.geeksforgeeks.org/java-threads/
- https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#stop-java.lang.Throwable-
- https://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html