Threading in java tutorial

Processes and Threads

In concurrent programming, there are two basic units of execution: processes and threads. In the Java programming language, concurrent programming is mostly concerned with threads. However, processes are also important.

A computer system normally has many active processes and threads. This is true even in systems that only have a single execution core, and thus only have one thread actually executing at any given moment. Processing time for a single core is shared among processes and threads through an OS feature called time slicing.

It’s becoming more and more common for computer systems to have multiple processors or processors with multiple execution cores. This greatly enhances a system’s capacity for concurrent execution of processes and threads — but concurrency is possible even on simple systems, without multiple processors or execution cores.

Processes

A process has a self-contained execution environment. A process generally has a complete, private set of basic run-time resources; in particular, each process has its own memory space.

Processes are often seen as synonymous with programs or applications. However, what the user sees as a single application may in fact be a set of cooperating processes. To facilitate communication between processes, most operating systems support Inter Process Communication (IPC) resources, such as pipes and sockets. IPC is used not just for communication between processes on the same system, but processes on different systems.

Читайте также:  No nlsxbe in java library path

Most implementations of the Java virtual machine run as a single process. A Java application can create additional processes using a ProcessBuilder object. Multiprocess applications are beyond the scope of this lesson.

Threads

Threads are sometimes called lightweight processes. Both processes and threads provide an execution environment, but creating a new thread requires fewer resources than creating a new process.

Threads exist within a process — every process has at least one. Threads share the process’s resources, including memory and open files. This makes for efficient, but potentially problematic, communication.

Multithreaded execution is an essential feature of the Java platform. Every application has at least one thread — or several, if you count «system» threads that do things like memory management and signal handling. But from the application programmer’s point of view, you start with just one thread, called the main thread. This thread has the ability to create additional threads, as we’ll demonstrate in the next section.

Источник

Java Multithreading Tutorial

Threads are the backbone of multithreading. We are living in a real-world which in itself is caught on the web surrounded by lots of applications. With the advancement in technologies we cannot achieve the speed required to run them simultaneously unless we introduce the concept of multi tasking efficiently. It is achieved by the concept of thread.

Real-life Example

Suppose you are using two tasks at a time on the computer, be it using Microsoft Word and listening to music. These two tasks are called processes. So you start typing in Word and at the same time start music app, this is called multitasking. Now you committed a mistake in a Word and spell check shows exception, this means Word is a process that is broken down into sub-processes. Now if a machine is dual-core then one process or task is been handled by one core and music is been handled by another core.

In the above example, we come across both multiprocessing and multithreading. These are somehow indirectly used to achieve multitasking. In this way the mechanism of dividing the tasks is called multithreading in which every process or task is called by a thread where a thread is responsible for when to execute, when to stop and how long to be in a waiting state. Hence, a thread is the smallest unit of processing whereas multitasking is a process of executing multiple tasks at a time.

Multitasking is being achieved in two ways:

  1. Multiprocessing: Process-based multitasking is a heavyweight process and occupies different address spaces in memory. Hence, while switching from one process to another, it will require some time be it very small, causing a lag because of switching. This happens as registers will be loaded in memory maps and the list will be updated.
  2. Multithreading: Thread-based multitasking is a lightweight process and occupies the same address space. Hence, while switching cost of communication will be very less.

Below is the Lifecycle of a Thread been illustrated

  1. New: When a thread is just created.
  2. Runnable: When a start() method is called over thread processed by the thread scheduler.
    • Case A: Can be a running thread
    • Case B: Can not be a running thread
  3. Running: When it hits case 1 means the scheduler has selected it to be run the thread from runnable state to run state.
  4. Blocked: When it hits case 2 meaning the scheduler has selected not to allow a thread to change state from runnable to run.
  5. Terminated: When the run() method exists or stop() method is called over a thread.

If we do incorporate threads in operating systems one can perceive that the process scheduling algorithms in operating systems are strongly deep-down working on the same concept incorporating thread in Gantt charts. A few of the most popular are listed below which wraps up all of them and are used practically in software development.

Now Imagine the concept of Deadlock in operating systems with threads – how the switching is getting computed over internally if one only has an overview of them.

So far we have understood multithreading and thread conceptually, so we can conclude advantages of multithreading before moving to any other concept or getting to programs in multithreading.

  • The user is not blocked as threads are independent even if there is an issue with one thread then only the corresponding process will be stopped rest all the operations will be computed successfully.
  • Saves time as too many operations are carried over at the same time causing work to get finished as if threads are not used the only one process will be handled by the processor.
  • Threads are independent though sharing the same address space.

So we have touched all main concepts of multithreading but the question striving in the head is left. why do we need it, where to use it and how? Now, we will discuss all three scenarios why multithreading is needed and where it is implemented via the help of programs in which we will be further learning more about threads and their methods. We need multithreading in four scenarios as listed.

Note: By default we only have one main thread which is responsible for main thread exception as you have encountered even without having any prior knowledge of multithreading

Two Ways to Implement Multithreading

Method 1: Using Thread Class

Java provides Thread class to achieve programming invoking threads thereby some major methods of thread class are shown below in the tabular format with which we deal frequently along the action performed by them.

Methods Action Performed
isDaemon() It checks whether the current thread is daemon or not
start() It starts the execution of the thread
run() It does the executable operations statements in the body of this method over a thread
sleep() It is a static method that puts the thread to sleep for a certain time been passed as an argument to it
wait() It sets the thread back in waiting state.
notify() It gives out a notification to one thread that is in waiting state
notifyAll() It gives out a notification to all the thread in the waiting state
setDaemon() It set the current thread as Daemon thread
stop() It is used to stop the execution of the thread
resume() It is used to resume the suspended thread.

Pre-requisites: Basic syntax and methods to deal with threads

Now let us come up with how to set the name of the thread. By default, threads are named thread-0, thread-1, and so on. But there is also a method that is often used as setName() method. Also corresponding to it there is a method getName() which returns the name of the thread be it default or settled already by using setName() method. The syntax is as follows:

(a) Returning the name of the thread

(b) Changing the name of the thread

public void setName(String name);

Taking a step further, let us dive into the implementation part to understand more concepts about multithreading. So, there are basically two ways of implementing multithreading:

Illustration: Consider if one has to multiply all elements by 2 and there are 500 elements in an array.

Java

Java

Java

Output:

Thread1 is running Thread2 is running

Here we have created our two thread classes for each thread. In the main method, we are simply creating objects of these thread classes where objects are now threads. So in main, we call thread using start() method over both the threads. Now start() method starts the thread and lookup for their run() method to run. Here both of our thread classes were having run() methods, so both threads are put to run state from runnable by the scheduler, and output on the console is justified.

Here we have created our two thread classes for each thread. In the main method, we are simply creating objects of these thread classes where objects are now threads. So in main, we call thread using start() method over both the threads. Now start() method starts the thread and lookup their run() method to run. Here only class 1 is having the run() method to make the thread transcend from runnable to run state to execute whereas thread 2 is only created but not put to run state by the scheduler as its corresponding run() method was missing. Hence, only thread 1 is called rest thread 2 is created only and is in the runnable state later blocked by scheduler because the corresponding run() method was missing.

Thread 2 Thread 1 is running

Method 2: Using Runnable Interface

Another way to achieve multithreading in java is via the Runnable interface. Here as we have seen in the above example in way 1 where Thread class is extended. Here Runnable interface being a functional interface has its own run() method. Here classes are implemented to the Runnable interface. Later on, in the main() method, Runnable reference is created for the classes that are implemented in order to make bondage with Thread class to run our own corresponding run() methods. Further, while creating an object of Thread class we will pass these references in Thread class as its constructor allows only one runnable object, which is passed as a parameter while creating Thread class object in a main() method. Now lastly just like what we did in Thread class, start() method is invoked over the runnable object who are now already linked with Thread class objects, so the execution begins for our run() methods in case of Runnable interface. It is shown in the program below as follows:

Источник

Defining and Starting a Thread

An application that creates an instance of Thread must provide the code that will run in that thread. There are two ways to do this:

    Provide a Runnable object. The Runnable interface defines a single method, run , meant to contain the code executed in the thread. The Runnable object is passed to the Thread constructor, as in the HelloRunnable example:

public class HelloRunnable implements Runnable < public void run() < System.out.println("Hello from a thread!"); >public static void main(String args[]) < (new Thread(new HelloRunnable())).start(); >>
public class HelloThread extends Thread < public void run() < System.out.println("Hello from a thread!"); >public static void main(String args[]) < (new HelloThread()).start(); >>

Notice that both examples invoke Thread.start in order to start the new thread.

Which of these idioms should you use? The first idiom, which employs a Runnable object, is more general, because the Runnable object can subclass a class other than Thread . The second idiom is easier to use in simple applications, but is limited by the fact that your task class must be a descendant of Thread . This lesson focuses on the first approach, which separates the Runnable task from the Thread object that executes the task. Not only is this approach more flexible, but it is applicable to the high-level thread management APIs covered later.

The Thread class defines a number of methods useful for thread management. These include static methods, which provide information about, or affect the status of, the thread invoking the method. The other methods are invoked from other threads involved in managing the thread and Thread object. We’ll examine some of these methods in the following sections.

Источник

Оцените статью