Open In App

Main App Implements Runnable | Concurrent Programming Approach 2

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

Prerequisite: Different Approaches to Concurrent Programming in Java

Let’s look at the second approach in detail.

  1. The user has the main class that implements runnable which is a promise to the compiler that the class will have a run method.
    public class MyClass implements Runnable{
        public void run(){
    
        }
    }
    
  2. The user then passes a reference to the main application to the execute method using the this keyword.
    taskList.execute(this)
    

    This is the way to convey to the compiler that when it gets around to running a particular task, call it’s the respective run method.

  3. The advantage of this approach over approach one is that the run method can call methods in the main application including the private ones.
  4. The disadvantage of this approach over first approach is race conditions. The reason we put the run method in the main application is so it can handle data in the main application. If the user starts more than one thread and they are simultaneously modifying the same shared data, then there are race conditions to worry about. Secondly, there is no constructor which makes it very hard to pass constructor arguments, thus each class starts off the same way.
  5. Sample Code: The user implements runnable in the main class and the same class also has a bunch of other methods for making the task queue and calling the execute method.

The following is the approach 2 implementation of the counterexample explained in approach one:




import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
  
// Concurrent Programming in action
public class MainAppRunnable implements Runnable {
  
    private final int loopLimit;
  
    // Limit till which the counter will run
    private MainAppRunnable(int loopLimit)
    {
        this.loopLimit = loopLimit;
    }
  
    private void startThreads()
    {
  
        // Made the task queue
        ExecutorService taskList
            = Executors.newFixedThreadPool(2);
  
        // Added these to the task queue
        // and made available for execution
        taskList.execute(this);
        taskList.execute(this);
        taskList.execute(this);
        taskList.execute(this);
        taskList.execute(this);
  
        // Stopped new tasks from being
        // added to the task queue
        taskList.shutdown();
    }
  
    @Override
    public void run()
    {
        for (int i = 0; i < loopLimit; i++) {
            System.out.println(
                Thread.currentThread().getName()
                + " Counter: " + i);
        }
  
        // Called private method that is
        // part of the same application
        pause(Math.random());
    }
  
    // Methods that run uses can be private
    // in this approach
    private void pause(double seconds)
    {
        try {
            Thread
                .sleep(Math.round(seconds * 1000.0));
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
  
    // Driver method
    public static void main(String[] args)
    {
        new MainAppRunnable(3).startThreads();
    }
}


Output:

pool-1-thread-1 Counter: 0
pool-1-thread-2 Counter: 0
pool-1-thread-1 Counter: 1
pool-1-thread-1 Counter: 2
pool-1-thread-2 Counter: 1
pool-1-thread-2 Counter: 2
pool-1-thread-2 Counter: 0
pool-1-thread-2 Counter: 1
pool-1-thread-2 Counter: 2
pool-1-thread-2 Counter: 0
pool-1-thread-2 Counter: 1
pool-1-thread-2 Counter: 2
pool-1-thread-1 Counter: 0
pool-1-thread-1 Counter: 1
pool-1-thread-1 Counter: 2


Last Updated : 08 Apr, 2019
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads