Multithreading executes tasks. The difference between Thread class, Runable interface and Callable interface

Mode 1:

Implementation principle:
Create a new Thread class TestThread, inherit the Thread class, rewrite the run method, instantiate the TestThread object in the main Thread, call the start() method of the object, and start a new Thread. The new Thread will automatically execute the code block of the run method. When the new Thread executes the run method depends on the adjustment of the CPU

Applicable scenarios:
Multiple threads execute their own tasks without disturbing each other. The parameters required by the task are set by the constructor when the thread class instantiates the object, such as multiple chefs frying different dishes

Traditional way

package com.wei.thread;

import java.util.HashMap;
import java.util.Map;

/**
 * @author: wei
 * @date 2022/5/3 21:58
 * explain:
 **/
public class TestThread extends Thread {

    private Map<String, Object> params;

    public TestThread(Map<String, Object> params) {
        this.params = params;
    }

    @Override
    public void run() {
        StringBuilder builder = new StringBuilder();
        params.forEach((k, v) -> {
            builder.append(v).append("|");
        });
        System.out.println(Thread.currentThread().getName() + "-> Materials used (" + builder.toString() + ") cook a dish");
    }

    public static void main(String[] args) {
        // Define recipe ingredients
        HashMap<String, Object> params1 = new HashMap<>();
        HashMap<String, Object> params2 = new HashMap<>();
        params1.put("tomato", "tomato");
        params1.put("egg", "egg");
        params2.put("beef", "beef");
        // When a thread class instantiates an object, it passes in parameters
        TestThread t1 = new TestThread(params1);
        t1.setName("Chef 1");
        TestThread t2 = new TestThread(params2);
        t2.setName("Chef 2");
        t1.start();
        t2.start();
    }
}

Lambda mode

package com.wei.thread;

import java.util.HashMap;

/**
 * @author: wei
 * @date 2022/5/3 21:58
 * explain:
 **/
public class TestThreadLambda {

    public static void main(String[] args) {
        HashMap<String, Object> params1 = new HashMap<>();
        HashMap<String, Object> params2 = new HashMap<>();
        params1.put("tomato", "tomato");
        params1.put("egg", "egg");
        params2.put("beef", "beef");
        Thread t1 = new Thread(() -> {
            StringBuilder builder = new StringBuilder();
            params1.forEach((k, v) -> {
                builder.append(v).append("|");
            });
            System.out.println(Thread.currentThread().getName() + "-> Materials used (" + builder.toString() + ") cook a dish");
        },"Chef 1");
        Thread t2 = new Thread(() -> {
            StringBuilder builder = new StringBuilder();
            params2.forEach((k, v) -> {
                builder.append(v).append("|");
            });
            System.out.println(Thread.currentThread().getName() + "-> Materials used (" + builder.toString() + ") cook a dish");
        }, "Chef 2");
        t1.start();
        t2.start();
    }
}

Mode 2:

Implementation principle:
Create a new TestRunable class, implement the Runable interface, rewrite the run method, and instantiate the TestRunable object in the main process; When instantiating a Thread object using a parameterized constructor, the TestRunable object is passed in as a parameter, and then the start() method of the Thread object is called to start a new Thread. The new Thread will automatically execute the code block of the run method. When the new Thread executes the run method depends on the scheduling of the CPU

Applicable scenarios:
A scenario in which multiple threads operate a task together or share common resources without knowing the task execution results. For example: praise the idol

Traditional way

package com.wei.thread;

/**
 * @author: wei
 * @date 2022/5/3 22:02
 * explain:
 **/
public class TestRunable implements Runnable {

    String idol;

    public TestRunable(String idol) {
        this.idol = idol;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " to" + idol + " give the thumbs-up");
    }

    public static void main(String[] args) {
        // Like the same idol
        TestRunable tr = new TestRunable("Jay Chou");
        // Users like idols
        Thread t1 = new Thread(tr, "Zhang San");
        Thread t2 = new Thread(tr, "Li Si");
        Thread t3 = new Thread(tr, "Wang Wu");
        t1.start();
        t2.start();
        t3.start();
    }
}

Lambda mode

package com.wei.thread;

/**
 * @author: wei
 * @date 2022/5/3 22:02
 * explain:
 **/
public class TestRunableLambda{

    /**
     * give the thumbs-up
     */
    public static void dianZan(String idol) {
        System.out.println(Thread.currentThread().getName() + " to" + idol + " give the thumbs-up");
    }

    public static void main(String[] args) {
        // Praise the idol
        Thread t1 = new Thread(()->{dianZan("Jay Chou");}, "Zhang San");
        Thread t2 = new Thread(()->{dianZan("Zhou conclusion");}, "Li Si");
        Thread t3 = new Thread(()->{dianZan("Zhou conclusion");}, "Wang Wu");
        t1.start();
        t2.start();
        t3.start();
    }
}

Mode 3:

Implementation principle:
Create a new TestCallable class, implement the Callable interface, rewrite the call method, and instantiate the TestCallable object in the main process; Proxy calls need to be made through the thread pool. The TestCallable object is submitted to the thread pool. The thread of the thread pool will automatically execute the code block of the call method. When the thread in the thread pool executes the call method depends on the scheduling of the CPU

Applicable scenarios:
Scenarios where multiple threads operate a task together or share the same resource, but the task execution results need to be returned, such as user ticket grabbing

Traditional way

package com.wei.thread;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * @author: wei
 * @date 2022/5/3 22:12
 * explain:
 **/
public class TestCallable implements Callable<Map<String, String>> {

    int ticket;

    public TestCallable(int ticket) {
        this.ticket = ticket;
    }

    @Override
    public Map<String, String> call() {
        Map<String, String> result = new HashMap<>();
        synchronized (this) {
            if (ticket <= 0) {
                result.put(Thread.currentThread().getName(), "Tickets have been sold out");
                return result;
            }
            result.put(Thread.currentThread().getName(), "Buy a ticket No:" + ticket);
            ticket--;
        }
        return result;
    }

    public static void main(String[] args) throws Exception{
        // 2 tickets
        TestCallable tc = new TestCallable(2);
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        // Simulate three users to grab tickets
        Future<Map<String, String>> user1 = threadPool.submit(tc);
        Future<Map<String, String>> user2 = threadPool.submit(tc);
        Future<Map<String, String>> user3 = threadPool.submit(tc);
        System.out.println(user1.get());
        System.out.println(user2.get());
        System.out.println(user3.get());
        threadPool.shutdown();
    }
}

Lambda mode

package com.wei.thread;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * @author: wei
 * @date 2022/5/3 22:12
 * explain:
 **/
public class TestCallableLambda {

    private static int ticket = 2;

    public static synchronized Map<String, String> buyTicket(String user) {
        Map<String, String> result = new HashMap<>();
        if (ticket <= 0) {
            result.put(user, "Tickets have been sold out");
            return result;
        }
        result.put(user, "Buy a ticket No:" + ticket);
        ticket--;
        return result;
    }

    public static void main(String[] args) throws Exception {

        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        // Simulate three users to grab tickets
        Future<Map<String, String>> user1 = threadPool.submit(() -> {
            return buyTicket("Zhang San");
        });
        Future<Map<String, String>> user2 = threadPool.submit(() -> {
            return buyTicket("Li Si");
        });
        Future<Map<String, String>> user3 = threadPool.submit(() -> {
            return buyTicket("Wang Wu");
        });
        System.out.println(user1.get());
        System.out.println(user2.get());
        System.out.println(user3.get());
        threadPool.shutdown();
    }
}

Summary:

1. The difference between Thread class, Runable interface and Callable interface

  • Inherit the Thread class, instantiate the Thread object, and call the start() method of the object to start the Thread
  • The class that implements the Runable interface or Callable interface needs to pass the object into the proxy object after instantiation as an object, and the proxy object starts the thread

2. Differences between Runable interface implementation class and Callable interface implementation class

  • The proxy object of the implementation class of the Runable interface can be a Thread object or a Thread pool object
  • The proxy object of the Callable interface implementation class can only be a thread pool object
  • The Runable interface implements the class. There is no return value after the task is executed
  • Callable interface implementation class, with return value after task execution

Tags: Java Multithreading

Posted by kishan on Wed, 04 May 2022 09:32:22 +0300