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