This article mainly introduces Java's use of ExecutorService to synchronously execute a large number of threads. ExecutorService can maintain the stability of our large number of threads when operating critical resources.
Since Java 1.5, the official website has launched a class like Executor. This class can maintain the stability of our large number of threads when operating critical resources.
Let’s start with a piece of code:
TestRunnable.java
public class TestRunnable implements Runnable { private String name; public TestRunnable(String name) { this.name = name; } @Override public void run() { while (true) { if (Main.Surplus < 0) return; Main.Surplus--; System.out.println(name + " " + Main.Surplus); } } }
main entrance
public static void main(String[] args) { TestRunnable runnable = new TestRunnable("runnable1"); TestRunnable runnable2 = new TestRunnable("runnable2"); Thread t1 = new Thread(runnable); Thread t2 = new Thread(runnable2); t1.start(); t2.start(); }
In this way, we can see, The data must be messed up. Of course, we can add a synchronized keyword at this time, but this will also cause some minor problems.
I plan to use a Java has a built-in thread management mechanism to solve this problem. The idea of solving this problem is probably that we maintain a thread pool. When there is a request for operation, they all enter the thread pool, and we only open one thread to allow the request to be made. Sequential execution and sequential calling of critical resources are very safe.
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class Main { public static int Surplus = 10; private ExecutorService executor = Executors.newSingleThreadExecutor(); void addTask(Runnable runnable) { executor.execute(runnable); } <V> V addTask(Callable<V> callable) { Future<V> submit = executor.submit(callable); try { return submit.get(); } catch (InterruptedException e) { System.out.println("InterruptedException" + e.toString()); } catch (ExecutionException e) { System.out.println("ExecutionException" + e.toString()); } return null; } public void testAddTask(String name) { addTask(new Runnable() { @Override public void run() { for (int i = 0; i < 3; i++) { if (Main.Surplus <= 0) return; Main.Surplus--; System.out.println(name + " " + Main.Surplus); } } }); } public void testAddTask2(String name) { int count = addTask(new Callable<Integer>() { @Override public Integer call() throws Exception { for (int i = 0; i < 3; i++) { if (Main.Surplus <= 0) return 0; Main.Surplus--; System.out.println(name + " " + Main.Surplus); } return Main.Surplus; } }); } public void close() { executor.shutdown(); } public static void main(String[] args) { Main main = new Main(); main.testAddTask("task1"); main.testAddTask2("task2"); main.testAddTask("task3"); main.testAddTask2("task4"); main.close(); } }
Here, we define two methods, namely addTask and generic addTask. The implementation principles of these two methods are the same. One of them has a callback and the other does not have a callback. , just depends on project requirements.
Then call these two methods respectively, and you can see that the results are very orderly and not chaotic.
The above is the detailed content of Detailed explanation of how Java uses ExecutorService to execute a large number of threads synchronously (picture). For more information, please follow other related articles on the PHP Chinese website!