1. Потоки и процессы
1.1 Разница между потоками и процессами
- процесс Это независимое пространство в памяти, которое отвечает за работу текущего приложения. Текущий процесс отвечает за планирование всех текущих деталей в текущей программе (операционная система выделяет независимое рабочее пространство для процесса);
- нить 它是位于进程中,负责当前进程中的某个具备独立运行资格的空间(进程为线程分配一块独立运行的空间); 进程是负责某个程序的执行,线程是负责进程中某个独立功能的运行,一个进程至少要包含一个线程。
- Многопоточность В процессе может быть открыто несколько потоков, что позволяет нескольким потокам выполнять задачу одновременно. Цель использования многопоточности — повысить эффективность выполнения программы.
1.2 Состояние выполнения потока
После того, как объект потока создан через класс Thread или интерфейс Runnable, он входит в начальное состояние, для входа в состояние runnable (состояние готовности) вызывается метод start, что в данный момент не является реальной операцией, а лишь означает, что различное оборудование перед запуском было подготовлено; если этот поток Когда квант времени ЦП получен, он входит в реальное рабочее состояние и выполняет бизнес-логику в методе запуска; если выполняется метод запуска или вызывается метод остановки , поток переполняется и переходит в мертвое состояние, вызывая различные методы в рабочем состоянии, он также войдет в другие разные состояния. Если вызывается метод принудительного запуска или метод сна, он войдет в состояние ожидания. По истечении времени , он автоматически перейдет в состояние готовности, готовый получить квант времени ЦП в любое время; если он увидит, что он синхронизирован, он войдет в состояние ожидания очереди синхронизации, или, если он вызовет метод ожидания, он войдет в состояние ожидания. состояние ожидания должно быть разбужено уведомлением, чтобы войти в состояние ожидания.Если другие потоки завершили выполнение, поток перейдет в состояние готовности после получения блокировки синхронизации, ожидая получения кванта времени процессора. Будет ли выполняться поток, можно определить только по тому, может ли он конкурировать за квант времени ЦП, но при повышении приоритета поток имеет более высокую вероятность выполнения первым. Справочный документ: https://mp.weixin.qq.com/s?src=11×tamp=1513562547&ver=581&signature=30FEkCCQvF3E1tt67vYVym5tRNsSk3d8HGe0v9TAonJmhLh4-53fDEBbgwNFOlgp5rAlGFAJQXYnviaFRwiQ9NmbtIWnZGpotGcuV0Ok*3WzWxg4X6e2mxU0JrgbRb&new=1
2. Многопоточность
Принцип многопоточной работы таков: процессор переключает кванты времени в потоках. ЦП отвечает за выполнение программы. Фактически, он может запускать только одну программу вместо нескольких программ в каждый момент времени. Он постоянно переключается между несколькими программами с высокой скоростью. Программа на самом деле представляет собой процесс или несколько потоков. На самом деле процессор продолжает переключаться между несколькими потоками на высокой скорости, а открытие нескольких потоков не позволяет процессору отдыхать и максимально выжимает его для обслуживания программы. Существует три способа достижения многопоточности: наследование класса Thread, реализация интерфейса Runnable, использование пула потоков.
2.1 Наследование класса Thread
public class MyExtendsThread extends Thread {
String flag;
public MyExtendsThread(String flag){
this.flag = flag;
}
@Override
public void run(){
String name = Thread.currentThread().getName();
System.out.println("线程"+name+"开始工作了...");
Random random = new Random();
for (int i = 0;i < 20;i++){
try {
Thread.sleep(random.nextInt(10)*100);
System.out.println(name+"============="+flag);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Thread t0 = new MyExtendsThread("t0");
Thread t1 = new MyExtendsThread("t1");
t0.start();
t1.start();
// t0.run();
// t1.run();
}
}
Метод запуска используется для вызова потока, а не метода запуска.Использование метода запуска предназначено только для вызова метода, а фактическое выполнение по-прежнему является основным потоком, и вызов метода запуска может четко видеть конфликт потока.
2.2 Реализация интерфейса Runnable
public class MyThreadImplementRunnable implements Runnable {
int x;
public MyThreadImplementRunnable(int x) {
this.x = x;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println("线程"+name+"开始执行");
Random random = new Random();
for(int i = 0;i<20;i++){
try {
Thread.sleep(random.nextInt(10)*100);
System.out.println(name+"============="+x);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new MyThreadImplementRunnable(1),"线程1");
Thread t2 = new Thread(new MyThreadImplementRunnable(2),"线程2");
t1.start();
t2.start();
}
}
2.3 Реализация интерфейса Callable
- Создайте класс MyThreadImplementCallable, реализующий интерфейс Callable;
- Создайте объект класса: MyThreadImplementCallable callable = new MyThreadImplementCallable("test");
- Создайте объект FutureTask из Callable: FutureTask futureTask = новая FutureTask (вызываемая); Примечание. FutureTask — это оболочка, созданная путем принятия Callable, которая реализует интерфейсы Future и Runnable.
- Создайте объект Thread из FutureTask: Поток потока = новый поток (futureTask);
- Начать ветку: поток.старт();
- Получить результат выполнения потока задачи будущеезадача.получить(); Примечание. Поток, реализующий интерфейс Callable, может получить результат выполнения потока задачи; поток, реализующий интерфейс Runnable, не может получить результат выполнения потока задачи.
public class MyThreadImplementCallable implements Callable<String> {
String name;
public MyThreadImplementCallable(String name) {
this.name = name;
}
@Override
public String call() throws Exception {
Thread thread = Thread.currentThread();
System.out.println(thread.getName()+"开始工作==============");
Random random = new Random();
Thread.sleep(random.nextInt(5)*100); //模拟执行业务
return name+":执行完成";
}
public static void main(String[] args) throws Exception{
MyThreadImplementCallable callable = new MyThreadImplementCallable("测试");
FutureTask<String> futureTask = new FutureTask<String>(callable);
Thread thread = new Thread(futureTask);
thread.start();
String result = futureTask.get(); //获取任务线程执行结果
System.out.println("线程的执行结果:"+result);
}
}
2.4 Использование пулов потоков
См. обсуждение пула потоков ниже. Справочный документ: https://www.cnblogs.com/langtianya/archive/2013/03/14/2959713.html
3. Синхронизация
3.1синхронизированное ключевое слово
public class MySynchronized {
public static void main(String[] args){
final MySynchronized synchronized1 = new MySynchronized();
final MySynchronized synchronized2 = new MySynchronized();
new Thread("thread1"){
@Override
public void run(){
synchronized (synchronized1){
try {
System.out.println(this.getName()+":start");
Thread.sleep(1000);
System.out.println(this.getName()+":wake up");
System.out.println(this.getName()+":end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread("thread2"){
@Override
public void run() {
synchronized (synchronized1){ //争抢同一把锁时,线程1没释放之前,线程2只能等待
// synchronized (synchronized2){ //如果不是一把锁,可以看到两句话交叉打印,发生争抢
System.out.println(this.getName()+":start");
System.out.println(this.getName()+":end");
}
}
}.start();
}
}
Synchronized — это ключевое слово в java и встроенная функция языка java. Если блок кода украшен синхронизацией, код синхронизируется. Когда поток получает блокировку и начинает выполнение, другие потоки могут только ждать выполнения потока, а затем снимать блокировку. Есть только два способа снять блокировку. Причины: 1. Поток выполняется нормально 2. При выполнении потока возникает исключение, и JVM автоматически снимает блокировку. Видно, что после использования ключевого слова synchronized только один поток выполняет общий код в блоке кода в каждый момент времени, что является потокобезопасным; недостаток также очевиден, другие потоки могут только ждать снятия блокировки, что серьезно тратит ресурсы.
3.2 Интерфейс блокировки
- Разница между блокировкой и синхронизацией: Блокировка не является встроенной в язык Java, это интерфейс, через который может быть достигнут синхронизированный доступ. Синхронизация — это ключевое слово в языке Java и встроенная функция. Блокировка сильно отличается от синхронизированной. требуют, чтобы пользователи вручную сняли блокировку, когда синхронизированный метод или блок синхронизированного кода выполняются, система автоматически позволит потоку освободить занятую блокировку; в то время как блокировка требует, чтобы пользователь вручную снял блокировку, если блокировка активно не снимается, она может привести к феномену взаимоблокировки. Lock — это интерфейс со следующими методами:
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
}
lock(), tryLock(), tryLock(long time, TimeUnit unit), lockInterruptably() используются для получения блокировок. Метод unLock() используется для снятия блокировки.
- lock используется для получения блокировок.Как упоминалось ранее, если вы используете Lock, вы должны активно снять блокировку. Даже если возникнет исключение, программа не снимет блокировку автоматически, поэтому, вообще говоря, использование Lock должно выполняться в блоке try{}catch{}, а операция снятия блокировки должна выполняться в блоке finally чтобы гарантировать, что блокировка должна быть освобождена, чтобы предотвратить взаимоблокировку.
public class MyLock {
private static ArrayList<Integer> arrayList = new ArrayList<Integer>();
private static Lock lock = new ReentrantLock();
public static <E> void main(String[] args) {
new Thread() {
@Override
public void run() {
Thread thread = Thread.currentThread();
lock.lock(); //获取锁
try {
System.out.println(thread.getName() + "得到了锁");
for (int i = 0; i < 5; i++) {
arrayList.add(i);
}
} catch (Exception e) {
} finally {
System.out.println(thread.getName() + "释放了锁");
lock.unlock(); //释放锁
}
};
}.start();
new Thread() {
@Override
public void run() {
Thread thread = Thread.currentThread();
lock.lock();
try {
System.out.println(thread.getName() + "得到了锁");
for (int i = 0; i < 5; i++) {
arrayList.add(i);
}
} catch (Exception e) {
} finally {
System.out.println(thread.getName() + "释放了锁");
lock.unlock();
}
};
}.start();
}
}
- tryLock() указывает, что он используется для попытки получения блокировки.Если получение прошло успешно, он возвращает true, а если получение не удалось (т. е. блокировка была получена другим потоком), он возвращает false, что означает что этот метод немедленно вернется, несмотря ни на что, если его нельзя получить. Он не ждет во время блокировки.
- Метод tryLock(долгое время, блок TimeUnit) аналогичен методу tryLock(). Разница в том, что этот метод будет ждать определенное время, пока блокировка не будет получена. Если блокировка не будет получена в течение установленного срока , он вернет false. Возвращает true, если блокировка была получена в начале или в течение периода ожидания.
//观察现象:一个线程获得锁后,另一个线程取不到锁,不会一直等待
public class MyTryLock {
private static List<Integer> arrayList = new ArrayList<Integer>();
private static Lock lock = new ReentrantLock();
public static void main(String[] args) {
new Thread("线程1") {
@Override
public void run() {
Thread thread = Thread.currentThread();
boolean tryLock = lock.tryLock();
System.out.println(thread.getName()+"======="+tryLock);
if(tryLock){
try {
System.out.println(thread.getName() + "得到了锁");
for(int i = 0;i < 20;i++){
arrayList.add(i);
}
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
System.out.println(thread.getName() + "释放了锁");
}
}
}
}.start();
new Thread("线程2") {
@Override
public void run() {
Thread thread = Thread.currentThread();
boolean tryLock = lock.tryLock();
System.out.println(thread.getName()+"======="+tryLock);
if(tryLock){
try {
System.out.println(thread.getName() + "得到了锁");
for(int i = 0;i < 20;i++){
arrayList.add(i);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
System.out.println(thread.getName() + "释放了锁");
}
}
}
}.start();
}
}
Поток 1 и поток 2 совместно используют переменную-член arrayList. Когда поток 1 получает блокировку, поток 2 не может получить блокировку и не может выполнить свою бизнес-логику. Только после того, как поток 1 завершит выполнение и освободит блокировку, поток 2 может получить блокировку. выполняет свой код, тем самым обеспечивая потокобезопасность.
- Метод lockInterruptably() является особым.При получении блокировки с помощью этого метода, если поток ожидает получения блокировки, поток может реагировать на прерывание, то есть на состояние ожидания потока прерывания. Обратите внимание, что когда поток получает блокировку, он не будет прерван методом interrupt(). Следовательно, когда блокировка получена с помощью метода lockInterruptably(), если ее невозможно получить, ее можно прервать только путем ожидания. При синхронизированной модификации, когда поток находится в состоянии ожидания блокировки, его нельзя прервать, и он может только ждать вечно.
- Класс реализации интерфейса Lock — ReentrantLock Если вы напрямую используете интерфейс блокировки, нам нужно реализовать много методов, что неудобно. ReentrantLock — единственный класс, реализующий интерфейс Lock, а ReentrantLock предоставляет больше методов. объект.
- ReadWriteLock также является интерфейсом, в котором определены только два метода:
public interface ReadWriteLock {
Lock readLock();
Lock writeLock();
}
Один для получения блокировки чтения и один для получения блокировки записи. Другими словами, операции чтения и записи файла разделены и разделены на две блокировки, которые должны быть назначены потокам, так что несколько потоков могут выполнять операции чтения одновременно.
- ReentrantReadWriteLock предоставляет множество многофункциональных методов, но есть два основных: readLock() и writeLock() используются для получения блокировок чтения и записи.Результат использования этой операции блокировки чтения-записи: завершается, выполняются все операции записи, и в середине не будет чередующихся операций чтения и записи.
/**
* @author 刘俊重
* 如果有一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁。
* 如果有一个线程已经占用了写锁,则此时其他线程如果申请写锁或者读锁,则申请的线程会一直等待释放写锁。
*/
public class MyReentrantReadWriteLock {
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public static void main(String[] args) {
final MyReentrantReadWriteLock myTest = new MyReentrantReadWriteLock();
new Thread("线程1"){
@Override
public void run(){
myTest.read(Thread.currentThread());
myTest.writer(Thread.currentThread());
}
}.start();
new Thread("线程2"){
@Override
public void run(){
myTest.read(Thread.currentThread());
myTest.writer(Thread.currentThread());
}
}.start();
}
/**
* @Description 读方法
* @Author 刘俊重
* @Date 2017/12/18
*/
private void read(Thread thread){
readWriteLock.readLock().lock();
try {
long start = System.currentTimeMillis();
while (System.currentTimeMillis()-start<=1){
System.out.println(thread.getName()+"===正在执行读操作");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();
System.out.println(thread.getName()+"==释放读锁");
}
}
/**
* @Description 写方法
* @Author 刘俊重
* @Date 2017/12/18
*/
private void writer(Thread thread){
readWriteLock.writeLock().lock();
try {
long start = System.currentTimeMillis();
while (System.currentTimeMillis()-start<=1){
System.out.println(thread.getName()+"===正在执行写操作");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.writeLock().unlock();
System.out.println(thread.getName()+"==释放写锁");
}
}
}
Замок и синхронизированный выбор:
- Lock — это интерфейс, а sysnchrinized — это ключевое слово java, принадлежащее реализации встроенного языка;
- Программа с синхронизированными ключевыми словами снимает блокировку после завершения операции или при возникновении исключения. Использование блокировки не снимает блокировку автоматически. Вы можете использовать команду разблокировки, чтобы снять ее самостоятельно, в противном случае это приведет к взаимоблокировке. Лучше всего снять блокировку. в конце концов;
- Используя блокировку, вы можете использовать метод trylock, чтобы определить, была ли получена блокировка, но это нельзя определить, используя синхронизированный;
- Использование lock может прервать поток, ожидающий блокировки, использование synchronized не может прервать поток, вы можете только ждать вечно;
- Использование блокировки может повысить эффективность многопоточных операций чтения. Вывод: если конкурирующие ресурсы не лютые, эффективность использования synchronized и lock одинакова, если одновременно конкурирует большое количество потоков, то lock гораздо лучше, чем synchronized.
4. изменчивое ключевое слово
程序执行时有主内存,每个线程工作时也有自己的工作内存。当一个线程开始工作时会从主内存中拷贝一个变量的副本到工作内存中,在工作内存中操作完副本时再更新回主内存。当存在多线程时,如果工作内存A处理完还没来得及更新回主内存之前,工作内存B就从主内存中拉取了这个变量,那么很明显这个变量并不是最新的数据,会出现问题。 Как это решить?可以使用volatile,volatile有个最显著的特性就是对它所修饰变量具有可见性,什么意思呢,就是当一个线程修改了变量的值,新的值会立刻(马上)同步到主内存中,其它线程使用时拉取到的就是最新的变量值。尽管volatile能保证变量的可见性,但并不能保证线程安全,因为它不能保证原子性。要想线程安全还是要用同步或者锁。 有一篇文档写volatile写的很好,贴一下:http://dwz.cn/76TMGW
5. Пул резьбы
После JDK1.5 были введены расширенные функции параллелизма.В пакете java.util.concurrent он специально используется для многопоточного параллельного программирования, в полной мере используя многопроцессорные и многоядерные функции современных компьютеров для написания больших параллельные приложения масштаба. В основном он включает атомарный вес, параллельные коллекции, синхронизаторы, повторные блокировки и обеспечивает мощную поддержку создания пулов потоков.
5.1 5 способов создать пул потоков
- Single Thread Executor: пул потоков только с одним потоком, все отправленные задачи выполняются последовательно; Код: Executors.newSingleThreadExecutor()
- Кэшированный пул потоков: в пуле потоков есть много потоков, которые необходимо выполнять одновременно. Старые доступные потоки будут инициированы новыми задачами для повторного выполнения. Если поток не выполняется в течение 60 секунд, он будет прекращено и удалено из пула; Код: Executors.newCachedThreadPool()
- Фиксированный пул потоков: пул потоков с фиксированным количеством потоков. Если задачи не выполняются, потоки всегда будут ждать. Код: Executors.newFixedThreadPool(4) Параметр 4 в конструкторе это размер пула потоков, его можно задать по желанию, лучше всего выставить в соответствии с количеством ядер процессора, получить количество ядер процессора int cpuNums = Runtime.getRuntime() .доступныепроцессоры();
- Запланированный пул потоков: пул потоков, используемый для планирования выполнения задач, не может выполняться напрямую. Он выполняется время от времени. Это стратегический тип. Код: Executors.newScheduledThreadPool()
- Single Thread Scheduled Pool : 只有一个线程,用来调度任务在指定时间执行,代码:Executors.newSingleThreadScheduledExecutor() Пример кода выглядит следующим образом:
public static void main(String[] args) {
ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
//获取cpu核心数
int num = Runtime.getRuntime().availableProcessors();
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(num);
ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(8);
ScheduledExecutorService newSingleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor();
}
5.2 Использование пула потоков
Прежде чем говорить об использовании пула потоков, давайте подчеркнем брата-близнеца Runnable, Callable, Они очень похожи, но метод run Runnable не будет иметь никаких возвращаемых результатов, а основной поток не может получить возвращаемое значение потока задачи; но метод вызова Callable Результат может быть возвращен, но основной поток блокируется при его получении, и ему нужно дождаться возврата потока задачи, чтобы получить результат, поэтому Callable более мощный, чем Runnable, так как получить результат исполнения? Ответ Future.Используя Future, вы можете получить результат выполнения Callable. Теперь давайте поговорим о том, как использовать пул потоков. Есть два способа: один — Runnable, а другой — Callable:
- Submit Runnable, объект Future возвращает null после завершения задачи, вызов execute, отправка задачи, анонимный Runable перезаписывает метод запуска, а метод запуска содержит бизнес-логику. Образец кода:
public class TestPoolWithRunnable {
public static void main(String[] args) throws Exception{
ExecutorService pool = Executors.newFixedThreadPool(4);
for (int i=0;i<10;i++){
Future<?> submit = pool.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "开始执行");
}
});
System.out.println("执行结果:"+submit.get()); //所有的执行结果全是null
}
pool.shutdown(); //关闭线程池
}
}
- Submit Callable, этот метод возвращает экземпляр Future для представления состояния задачи, вызов submit для отправки задачи, анонимный Callable, переписывание метода вызова, есть возвращаемое значение, получение возвращаемого значения будет заблокировано, пока задача потока не вернется результат.
/**
* @author 刘俊重
* Callable 跟Runnable的区别:
* Runnable的run方法不会有任何返回结果,所以主线程无法获得任务线程的返回值
* Callable的call方法可以返回结果,但是主线程在获取时是被阻塞,需要等待任务线程返回才能拿到结果
*/
public class TestPoolWithCallable {
public static void main(String[] args) throws Exception{
ExecutorService pool = Executors.newFixedThreadPool(4);
for(int i=0;i<10;i++){
Future<String> future = pool.submit(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(500);
return "===="+Thread.currentThread().getName();
}
});
//从Future中get结果,这个方法是会被阻塞的,一直要等到线程任务返回结果
System.out.println("执行结果:"+future.get());
}
pool.shutdown();
}
}
Как решить проблему получения блокировки результата выполнения? При использовании метода future.get() для получения результата этот метод блокируется, как повысить эффективность? Если вам не нужно получать результат выполнения немедленно, вы можете сначала поставить результат выполнения в очередь и получить результат выполнения каждого потока после выполнения программы.Пример кода выглядит следующим образом:
public class TestThreadPool {
public static void main(String[] args) throws Exception{
Future<?> submit = null;
//创建缓存线程池
ExecutorService cachePool = Executors.newCachedThreadPool();
//用来存在Callable执行结果
List<Future<?>> futureList = new ArrayList<Future<?>>();
for(int i = 0;i<10;i++){
//cachePool提交线程,Callable,Runnable无返回值
//submit = cachePool.submit(new TaskCallable(i));
submit = cachePool.submit(new TaskRunnable(i));
//把这些执行结果放到list中,后面再取可以避免阻塞
futureList.add(submit);
}
cachePool.shutdown();
//打印执行结果
for(Future f : futureList){
boolean done = f.isDone();
System.out.println(done?"已完成":"未完成");
System.out.println("线程返回结果:"+f.get());
}
}
}
Поместите submit в набор списка и возьмите его после того, как нить будет прямой.
6. Резюме параллельного программирования на Java
6.1 Недостатки отказа от использования пулов потоков
Непосредственное использование new Thread().start() не представляет проблемы для общих сценариев, но если есть много одновременных запросов, могут возникнуть скрытые опасности:
- Стоимость создания нового потока. Хотя поток намного легче процесса, для JVM стоимость создания нового потока по-прежнему очень высока, что определенно отличается от создания нового объекта.
- потребление ресурсов. Без пула для ограничения количества потоков количество потоков напрямую зависит от параллелизма приложения.
- стабильность. Стабильность становится проблемой, когда количество потоков превышает возможности системных ресурсов.
6.2 Тип пула резьбы
Независимо от того, создаете ли вы пул потоков с помощью Executors или управляете им с помощью Spring, вы должны знать, какие виды пулов потоков существуют:
- FixedThreadPool: пул потоков фиксированной длины, создание потоков при отправке задач до максимальной емкости пула, если какие-либо потоки неожиданно завершатся, будут добавлены новые потоки;
- CachedThreadPool: переменный пул потоков, который похож на пружину.Если нет спроса на задачу, он перезапускает простаивающие потоки.Если спрос увеличивается, потоки добавляются по мере необходимости, а размер пула не ограничен;
- SingleThreadExecutor: один поток. Задачи, которые не могут быть обработаны, попадут в очередь FIFO и будут ждать выполнения;
- ScheduledThreadPool: периодический пул потоков. Поддержка выполнения периодических задач потока На самом деле, эти различные типы пулов потоков дополняются построением ThreadPoolExecutor, разница заключается в параметрах corePoolSize, maxPoolSize, keepAliveTime, unit, workQueue, threadFactory.
6.3 Стратегия насыщения пула потоков
Из вышеуказанных типов нитей бассейнов, кроме CachedThreadpool Другое пул резьбы может иметь насыщенную, ненасыщенную необходимость, когда запрос на обработку политики, соответствующий потоку задач, например, достигает верхнего предела, установленного отклоненной задачей ThreadPoolExecuTor.SetrejectedexecutionHuctionHandhandher Methodes, JDK Он обеспечивает аборполицию, Callerrunspolicy, DiscardPolicy, DiscardoldestPolicy Zero Novel Contruge.