Examples of multithreaded programming in Java

  • 2020-04-01 04:12:36
  • OfStack

Java create threads (Runnable interface and Thread class)
In most cases, a Thread is created by instantiating a Thread object. Java defines two ways:

Implement the Runnable interface; You can inherit the Thread class.

The following describes each in turn.
Implement the Runnable interface

The easiest way to create a thread is to create a class that implements the Runnable interface. Runnable abstracts a unit of execution code. You can create threads for each object by implementing the methods of the Runnable interface. To implement the Runnable interface, a class only needs to implement a simple method called run(), which is declared as follows:


  public void run( )


In run(), you can define code to build new threads. It's important to understand that the run() method can call other methods, reference other classes, and declare variables just like the main thread. The only difference is that run() establishes another concurrent thread execution entry in the program. When run() returns, the thread ends.

After you have created the class that implements the Runnable interface, you instantiate an object of the Thread class within the class. The Thread class defines several constructors. Here's what we'll use:


  Thread(Runnable threadOb, String threadName)


In this constructor, threadOb is an instance that implements the Runnable interface class. This defines the starting point for thread execution. The name of the new thread is defined by threadName.

When a new Thread is created, it does not run until its start() method, which is defined in the Thread class, is invoked. Essentially, start() performs a call to run(). The Start () method is declared as follows:


  void start( )

The following example is to create a new thread and start it running:


// Create a second thread.
class NewThread implements Runnable {
  Thread t;
  NewThread() {
    // Create a new, second thread
    t = new Thread(this, "Demo Thread");
    System.out.println("Child thread: " + t);
    t.start(); // Start the thread
  }

  // This is the entry point for the second thread.
  public void run() {
    try {
      for(int i = 5; i > 0; i--) {
        System.out.println("Child Thread: " + i);
        Thread.sleep(500);
      }
    } catch (InterruptedException e) {
      System.out.println("Child interrupted.");
    }
    System.out.println("Exiting child thread.");
  }
}

class ThreadDemo {
  public static void main(String args[]) {
    new NewThread(); // create a new thread
    try {
      for(int i = 5; i > 0; i--) {
        System.out.println("Main Thread: " + i);
        Thread.sleep(1000);
      }
    } catch (InterruptedException e) {
      System.out.println("Main thread interrupted.");
    }
    System.out.println("Main thread exiting.");
  }
}

In the NewThread constructor, the NewThread object is created by the following statement:


  t = new Thread(this, "Demo Thread");


The previous statement this indicates that in this object you want the new thread to call the run() method. Then, start() is called, starting the execution of the thread with the run() method. This causes the child thread for loop to begin execution. After calling start(), the constructor for NewThread returns to main(). When the main thread is restored, it reaches the for loop. The two threads continue to run, sharing the CPU, until their loop ends. The output of the program is as follows:


Child thread: Thread[Demo Thread,5,main]
Main Thread: 5
Child Thread: 5
Child Thread: 4
Main Thread: 4
Child Thread: 3
Child Thread: 2
Main Thread: 3
Child Thread: 1
Exiting child thread.
Main Thread: 2
Main Thread: 1
Main thread exiting.

As mentioned earlier, in multithreaded programs, the main thread must usually be the last thread to finish running. In fact, on some older JVMS, the Java runtime system might "hang" if the main line ends before the child threads. The program guarantees the end of the main thread because the primary thread sleeps for 1000 milliseconds and the child thread for 500 milliseconds. This causes the child thread to end before the main thread ends. In short, you'll see a better way to wait for the thread to end.
Extending Thread

Another way to create threads is to create a new class to extend the Thread class, and then create an instance of that class. When a class inherits a Thread, it must override the run() method, which is the entry for the new Thread. It must also call the start() method to start a new thread execution. The following overrides the previous program with the extension thread class:


// Create a second thread by extending Thread
class NewThread extends Thread {
  NewThread() {
    // Create a new, second thread
    super("Demo Thread");
    System.out.println("Child thread: " + this);
    start(); // Start the thread
  }

  // This is the entry point for the second thread.
  public void run() {
    try {
      for(int i = 5; i > 0; i--) {
        System.out.println("Child Thread: " + i);
        Thread.sleep(500);
      }
    } catch (InterruptedException e) {
      System.out.println("Child interrupted.");
    }
    System.out.println("Exiting child thread.");
  }
}

class ExtendThread {
  public static void main(String args[]) {
    new NewThread(); // create a new thread
    try {
      for(int i = 5; i > 0; i--) {
        System.out.println("Main Thread: " + i);
        Thread.sleep(1000);
      }
    } catch (InterruptedException e) {
      System.out.println("Main thread interrupted.");
    }
    System.out.println("Main thread exiting.");
  }
}

The program produces the same output as the previous version. Child threads are generated by instantiating the NewThread object, which is derived from the Thread class. Notice the call to super() in NewThread. This method calls the Thread constructor in the following form:


  public Thread(String threadName)


Here, threadName specifies the threadName.
Choose the right method

At this point, you must be wondering why Java has two ways to create child threads, which is better. All the problems boil down to one point. The Thread class defines a variety of methods that can be overridden by derived classes. For all methods, the only one that must be overloaded is the run() method. This is of course the same method required to implement the Runnable interface. Many Java programmers believe that classes should be extended only when they are strengthened or modified. Therefore, if you do not reload other methods of Thread, it is best to implement only the Runnable interface. It's up to you, of course. However, in the rest of this chapter, we apply classes that implement the runnable interface to create threads.


Related articles: