You are probably familiar with multitasking, which is when someone tries to perform two or more tasks simultaneously. While people are not very good at multitasking, it turns out that computers are! It has become increasingly commonplace for computer systems to have multiple processors, or processors with multiple execution cores, which greatly enhances a system’s capacity for concurrent execution of processes and threads.
This process is possible even on simple systems, with only one processor or execution core. In software terms, performing multiple tasks at the same time is called concurrency. Concurrency may also be defined as the ability to run several programs or several parts of a program in parallel.
You will be happy to know that the Java platform is designed from the ground up to support concurrent programming, with basic concurrency support across the Java programming language as well as Java class libraries. Since version 5.0, the Java platform has also included high-level concurrency APIs. We will discuss this concept further in this programming tutorial.
Read: Best Online Courses to Learn Java
Processes versus Java Threads
In concurrent programming, there are two basic types of execution: processes and threads. In Java, concurrent programming is mostly achieved using threads. However, processes also play an important role.
A computer system normally has many active processes and threads running at any given moment, especially as computer systems with multiple processors have become the norm; more processors greatly enhances a system’s capacity for concurrent execution of processes and threads. Even in systems that only have a single core, and can only have one thread executing at any given moment, processes and threads may be shared through an OS feature called time slicing.
What are Processes in Multithreading?
A process has a self-contained execution environment. Because of this, a process generally has a complete, private set of run-time resources, such as memory space. Processes do not have a one-to-one relationship with programs or applications, as, often, a single application may be comprised of a set of cooperating processes. Communication between processes is achieved via Inter Process Communication (IPC) resources, which include pipes and sockets. IPC may be employed for communication between processes on the same system, or even on different systems.
Most implementations of the Java Virtual Machine run as a single process, but Java applications can create additional processes using a ProcessBuilder object.
What are Threads in Multithreading?
Threads are often referred to as lightweight processes and are similar to regular processes, as both provide an execution environment. However, creating a new thread requires fewer resources than creating a new process.
Threads exist within a process, meaning that every process has at least one thread. All threads within a process share its resources, including memory and open files. As such, threads are highly efficient, but can be problematic if not handled with care.
Multithreaded execution is an essential feature of the Java platform, making it ideal for concurrent programming. Every application starts with just one thread, called the main thread. From there, programmers can create additional threads, as we will see in the next section.
Defining and Starting a Thread in Java
In Java, each thread is associated with an instance of the Thread class. Hence, an application can spawn a new thread by creating an instance of Thread and then providing the code that will run in that thread. There are two ways to achieve this:
- Provide a Runnable object: The Runnable interface defines a single method – run – that is meant to contain the code executed in the thread. The Runnable object is passed to the Thread constructor, as in the following example:
public class HelloWorldRunnableExample implements Runnable { public void run() { System.out.println("Hello from a thread!"); } public static void main(String args[]) { (new Thread(new HelloWorldRunnableExample())).
start(); } } - Subclass Thread: The Thread class itself implements Runnable, though its run method does nothing. An application can subclass Thread, providing its own implementation of run, as shown in the code example below:
public class HelloWorldThreadExample extends Thread { public void run() { System.out.println("Hello from a thread!"); } public static void main(String args[]) { (new HelloWorldThreadExample()).
start(); } }
In both cases, the programs invoke Thread.start() to start the new thread.
How to Pause Thread Execution
Developers can suspend thread execution for a specified period using the static Thread.sleep() method. This is a simple way to give more processor time for the other threads of an application or even other applications that might be running on the same device. A second use of the sleep() method is to control the pacing of an application, as shown below:
public class SleepExample { public static void main(String args[]) throws InterruptedException { String lyrics[] = { "Signals transmitted", "Message received", "Reaction making impact", "Invisibly" }; for (int i = 0; i < lyrics.length; i++) { //Print a message every 2 seconds Thread.sleep(2000); System.out.println(lyrics[i]); } } }
Notice that the main() method declares that it throws InterruptedException. This is an exception that sleep throws when another thread interrupts the current thread while sleep is in progress.
Final Thoughts on Concurrency in Java
This programming tutorial covered some of the basics of concurrent programming with Java, including how to create a thread and temporarily suspend its execution. When working in a multithreaded environment, be aware that problems can occur if a thread attempts to read shared data which is later changed by another thread. Issues may also occur if several threads try to access and change the same data at the same time. Both conditions are serious, as they can lead to execution deadlocks and data corruption.
Now that you know the basics of concurrency in Java, check out our tutorial on Best Practices for Multithreading in Java.