multithreading
There are three main ways to realize multithreading
- extends Thread
- implements Runnable
- implements Callable
Implement interface VS inheritance Thread
It is better to implement the interface because:
- Java does not support multiple inheritance, so if you inherit Thread, you cannot inherit other classes, but you can implement multiple interfaces.
- The class might just need to be executable, and inheriting the entire Thread class would be too expensive.
-
extends Thread
Inheriting Thread code
public class ExtendsThread extends Thread {
/** * Thread name */
private String threadName;
/** * constructor **@paramThreadName specifies the threadName */
public ExtendsThread(String threadName) {
this.threadName = threadName;
}
/** * rewrite the run mode */
@Override
public void run(a) { System.out.println(threadName); }}Copy the code
public class ThreadMain {
public static void main(String[] args) {
ExtendsThread extendsThread = new ExtendsThread("1");
extendsThread.start();
extendsThread = new ExtendsThread("2"); extendsThread.start(); }}Copy the code
-
implements Runnable
Implement the Runnable interface
public class ThreadMain {
public static void main(String[] args) {
ThreadImplRunnable threadImplRunnable = new ThreadImplRunnable("Thread1");
new Thread(threadImplRunnable).start();
threadImplRunnable = new ThreadImplRunnable("Thread2");
new Thread(threadImplRunnable).start();
System.out.println("end"); }}Copy the code
public class ThreadImplRunnable implements Runnable {
/** * Thread name */
private String threadName;
/** * constructor **@paramThreadName specifies the threadName */
public ThreadImplRunnable(String threadName) {
this.threadName = threadName;
}
/** * override the run method */
@Override
public void run(a) { System.out.println(threadName); }}Copy the code
end
Thread1
Thread2
Copy the code
-
implements Callable
Futuretask.get () gets the returned value
public class ThreadImplCallable<T> implements Callable<T> {
/** * Thread name */
private String threadName;
/** * constructor **@paramThreadName specifies the threadName */
public ThreadImplCallable(String threadName) {
this.threadName = threadName;
}
/** * Override the call method */
@Override
public T call(a) throws Exception {
System.out.println(threadName);
return(T)threadName; }}Copy the code
public class ThreadMain {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<String> threadImplCallable = new ThreadImplCallable<>("Thread1");
FutureTask<String> futureTask = new FutureTask<>(threadImplCallable);
Thread thread = new Thread(futureTask);
thread.start();
String rValue = futureTask.get();
System.out.println("Thread1 return value is " + rValue);
threadImplCallable = new ThreadImplCallable<>("Thread2");
futureTask = new FutureTask<>(threadImplCallable);
thread = new Thread(futureTask);
thread.start();
rValue = futureTask.get();
System.out.println("Thread2 return value is " + rValue);
System.out.println("end"); }}Copy the code
Thread1
Thread1 return value is Thread1
Thread2
Thread2 return value is Thread2
end
Copy the code
The thread pool
The top-level interface of the Java thread pool is Executor, which defines only one method, execute. The Executor interface is inherited from the ExecutorService interface, and other related interfaces are defined. ExecutorService includes an abstract class AbstractExecutorService and ScheduledExecutorService, which implements the scheduling interface. Two classes inherit abstract classes. ThreadPoolExecutor and ForkJoinPool, whereas ScheduledThreadPoolExecutor implement interface implementation ScheduledExecutorService interfaces and inheritance ThreadPoolExecutor class, The basic relationship is like this, and the basic common encapsulation methods are in the Executors class, so long as Executors. XXXX can apply the corresponding encapsulation method.
Executor
Executors manage the execution of multiple asynchronous tasks without requiring programmers to explicitly manage the thread lifecycle. Asynchronous here refers to the execution of multiple tasks without interference, without the need for synchronous operations.
Thread pool type
-
newSingleThreadExecutor
A single thread pool. This thread pool has only one thread working, which is equivalent to a single thread executing all tasks in serial. If the unique thread terminates due to an exception, a new thread will replace it. This thread pool ensures that all tasks are executed in the order in which they were submitted.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool {
public static void main(String[] args) {
ExecutorService pool = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
pool.execute(() -> {
System.out.println(Thread.currentThread().getName() + "\t start...."); }); }}}Copy the code
Pool-1-thread-1:.... Pool-1-thread-1:.... Pool-1-thread-1:.... Pool-1-thread-1:.... Pool-1-thread-1:.... Pool-1-thread-1:.... Pool-1-thread-1:.... Pool-1-thread-1:.... Pool-1-thread-1:.... Pool-1-thread-1:....Copy the code
-
newFixedThreadPool
Create a thread pool of fixed size. A thread is created each time a task is submitted until the thread reaches the maximum size of the thread pool. The size of the thread pool stays the same once it reaches its maximum size, and if a thread terminates due to execution exceptions, a new thread is added to the pool.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
pool.execute(() -> {
System.out.println(Thread.currentThread().getName() + "\t start...."); }); }}}Copy the code
pool-1-thread-1Start the train.... pool-1-thread-4Start the train.... pool-1-thread-3Start the train.... pool-1-thread-2Start the train.... pool-1-thread-6Start the train.... pool-1-thread-7Start the train.... pool-1-thread-5Start the train.... pool-1-thread-8Start the train.... pool-1-thread-9Start the train.... pool-1-thread-10Start the train....Copy the code
-
newCachedThreadPool
Create a cacheable thread pool. If the size of the thread pool exceeds the number of threads needed to process the task, some of the idle threads are reclaimed, and as the number of tasks increases, new threads are added to the pool to process the task.
public static void main(String[] args) {
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
pool.execute(() -> {
System.out.println(Thread.currentThread().getName() + "\t start...."); }); }}Copy the code
Pool-1-thread-1:.... Pool-1-thread-2:.... Pool-1-thread-2:.... Pool-1-thread-3:.... Pool-1-thread-3:.... Pool-1-thread-1:.... Pool-1-thread-7:.... Pool-1-thread-5:.... Pool-1-thread-6:.... Pool-1-thread-4:....Copy the code
-
newScheduledThreadPool
This thread pool supports the need to execute tasks regularly and periodically.
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPool {
public static void main(String[] args) {
ScheduledExecutorService pool = Executors.newScheduledThreadPool(10);
for (int i = 0; i < 10; i++) {
pool.schedule(() -> {
System.out.println(Thread.currentThread().getName() + "\t start....");
}, 10, TimeUnit.SECONDS); }}}Copy the code
Pool-1-thread-1:.... Pool-1-thread-2:.... Pool-1-thread-1:.... Pool-1-thread-3:.... Pool-1-thread-7:.... Pool-1-thread-8:.... Pool-1-thread-6:.... Pool-1-thread-5:.... Pool-1-thread-2:.... Pool-1-thread-4:....Copy the code
If you want to execute a periodic task, you can do it once per second.
public static void main(String[] args) {
ScheduledExecutorService pool = Executors.newScheduledThreadPool(10);
/ / pool. ScheduleWithFixedDelay can also
pool.scheduleAtFixedRate(() -> {
System.out.println(Thread.currentThread().getName() + "\t start....");
}, 1.1, TimeUnit.SECONDS);
}
Copy the code
Pool-1-thread-1:.... Pool-1-thread-1:.... Pool-1-thread-2:.... Pool-1-thread-1:.... Pool-1-thread-3:.... Pool-1-thread-2:.... Pool-1-thread-4:.... Pool-1-thread-1:.... Pool-1-thread-5:.... Pool-1-thread-3:.... Pool-1-thread-3:.... Pool-1-thread-3:.... Pool-1-thread-3:.... Pool-1-thread-3:.... Pool-1-thread-3:.... Pool-1-thread-3:.... Pool-1-thread-9:.... Pool-1-thread-9:....Copy the code
-
newWorkStealingPool
NewWorkStealingPool is a jdk1.8 product that dynamically creates and closes threads based on the desired level of parallelism, reducing contention by using multiple queues, with the underlying ForkJoinPool implemented. ForkJoinPool takes advantage of multi-CPU, multi-core cpus by splitting a task into multiple “small tasks” that can be executed in parallel on multiple processor cores. When multiple “small tasks” are completed, combine the results.
NewWorkStealingPool is suitable for use in time-consuming operations, but newWorkStealingPool is not an extension of ThreadPoolExecutor. It is an extension of the new thread pool class ForkJoinPool. However, all of them are implemented in the same Executors class, so they are suitable for time-consuming tasks due to reasonable use of CPU for task operation (parallel operation)
package org.jeecg.modules.exam.entity;
import org.junit.Test;
import java.util.concurrent.*;
public class WorkStealingPoolTest {
/ / the number of threads
private static final int threads = 10;
// This is used to count whether a thread has completed execution
CountDownLatch countDownLatch = new CountDownLatch(threads);
/**
* newFixedThreadPool execute
*
* @throws ExecutionException
* @throws InterruptedException
*/
@Test
public void test1(a) throws ExecutionException, InterruptedException {
System.out.println("---- start ----");
ExecutorService executorService = Executors.newWorkStealingPool();
for (int i = 0; i < threads; i++) {
executorService.execute(() -> {
try {
System.out.println(Thread.currentThread().getName());
} catch (Exception e) {
System.out.println(e);
} finally{ countDownLatch.countDown(); }}); } countDownLatch.await(); System.out.println("---- end ----");
}
/** * newFixedThreadPool submit submit */
@Test
public void test2(a) throws InterruptedException {
System.out.println("---- start ----");
ExecutorService executorService = Executors.newWorkStealingPool();
for (int i = 0; i < threads; i++) {
// Callable with return value
executorService.submit(new Thread(new Runnable() {
@Override
public void run(a) {
try {
System.out.println(Thread.currentThread().getName());
} catch (Exception e) {
e.printStackTrace();
} finally{ countDownLatch.countDown(); }}})); } countDownLatch.await(); System.out.println("---- end ----");
}
/**
* newFixedThreadPool submit Callable
*
* @throws ExecutionException
* @throws InterruptedException
*/
@Test
public void test3(a) throws ExecutionException, InterruptedException {
System.out.println("---- start ----");
ExecutorService executorService = Executors.newWorkStealingPool();
for (int i = 0; i < threads; i++) {
// Runnable returns a valueFutureTask<? > futureTask =new FutureTask<>(new Callable<String>() {
/**
* call
* @return currentThreadName
*/
@Override
public String call(a) {
returnThread.currentThread().getName(); }}); executorService.submit(new Thread(futureTask));
System.out.println(futureTask.get());
}
System.out.println("---- end ----"); }}Copy the code