青春过了一大半,原来只是陪时间玩耍------第一期学习笔记!!!
细说Executors
- Executors类的基本信息
- Executors类中的方法
- 静态方法------>返回值为Callable的
- 静态方法------------>>>>返回值为ThreadFactory
- 静态方法------------>>>>返回值为ExecutorService
- static ExecutorService newCachedThreadPool()
- static ExecutorService newCachedThreadPool(**ThreadFactory threadFactory**)
- static ExecutorService newFixedThreadPool(int nThreads)
- static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
- static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
- 静态方法------------>>>>返回值为ExecutorService
- 简单研究一下scheduleAtFixedRate与scheduleWithFixedDelay
- newSingleThreadExecutor
- newSingleThreadScheduledExecutor
Executors类的基本信息
继承实现关系------->>>>>>
public class Executors extends Object
描述----<<<<<
java.util.concurrent.包中定义的执行程序、执行者服务、计划执行者服务、线程工厂和可调用类的工厂和实用方法。此类支持以下方法:
创建和返回使用通常有用的配置设置的执行者服务的方法。
使用通常有用的配置设置创建和返回计划执行服务的方法。
创建并返回"包装"执行者服务的方法,通过使无法访问特定于实施的方法来禁用重新配置。
创建并返回将新创建的线程设置为已知状态的线程工厂的方法。
从其他类似关闭的表单创建和返回可调用的方法,因此可用于需要执行方法。
Executors类中的方法
查看API发现没有显式的定义构造方法,其中该类中的方法都为静态方法,这一点跟LockSupport类似;
静态方法------>返回值为Callable的
static Callable callable(Runnable task)
static Callable callable(Runnable task)
返回可调用对象,当调用时,该对象运行给定任务并返回 null
返回值为Callable,但是返回值为null;
import java.util.concurrent.*;
public class FutureTaskDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<Object> th = Executors.callable(new Runnable() {
@Override
public void run() {
System.out.println("我不带结果");
}
});
FutureTask ft = new FutureTask(th);
Thread thread = new Thread(ft);
thread.start();
if (null == ft.get()) {
System.out.println("真的不带结果");
}
}
}
分析------->>>
static Callable callable(Runnable task, T result)
static Callable callable(Runnable task, T result)
返回可调用对象(当调用时)运行给定任务并返回给定结果。当应用需要对其他无结果的行动进行方法时,这很有用。
跟上面类似,只不过带了返回值
package com.gavin;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo {
public static void main(String[] args) throws Exception {
String result="结束";
Callable<Object> callable = Executors.callable(() -> {
System.out.println("执行完毕");
},result);
Object call = callable.call();
System.out.println(call);//结束
}
}
static Callable callable(PrivilegedAction<?> action)
返回可调用对象(当调用时)运行给定特权操作并返回其结果。
//callable(PrivilegedAction<?> action)
PrivilegedAction p = new PrivilegedAction() {
@Override
public Object run() {
//定义权限条件
return "需要满足权限条件来触发一些特权";
}
};
Callable<Object> ca = Executors.callable(p);
FutureTask futureTask = new FutureTask(ca);
Thread thread1 = new Thread(futureTask);
thread1.start();
Object o = futureTask.get();
System.out.println(o);
static Callable callable(PrivilegedExceptionAction<?> action)
static Callable callable(PrivilegedExceptionAction<?> action)
返回可调用对象(当调用时**)运行给定特权异常操作**并返回其结果。
PrivilegedExceptionAction pp = new PrivilegedExceptionAction() {
@Override
public Object run() throws Exception {
return "特权异常怎么处理";
}
};//可以用Lambada
Callable<Object> cal = Executors.callable(pp);
FutureTask<Object> objectFutureTask = new FutureTask<>(cal);
new Thread(objectFutureTask).start();
System.out.println(objectFutureTask.get());
静态方法------------>>>>返回值为ThreadFactory
static ThreadFactory defaultThreadFactory()
static ThreadFactory defaultThreadFactory()
返回用于创建新线程的默认线程工厂。
//线程工厂用于创建新线程,该线程非守护线程优先级也是线程组中允许的较小和最大优先级.默认为Default
//新线程的名称可通过线程.getName()的池-N线程-M(N)访问,其中N是本工厂的序列号,M是该工厂创建的线程的序列号。
ThreadFactory threadFactory = Executors.defaultThreadFactory();
Thread thread2 = threadFactory.newThread(() -> {
System.out.println("开第一个新线程");
});
Thread thread3 = threadFactory.newThread(() -> {
System.out.println("开第二个新线程");
});
thread2.start();
thread3.start();
System.out.println(thread2.getName());//pool-1-thread-1
System.out.println(thread3.getName());//pool-1-thread-2
分析------------>>>>
静态方法------------>>>>返回值为ExecutorService
static ExecutorService newCachedThreadPool()
static ExecutorService newCachedThreadPool()
创建一个线程池,根据需要创建新线程,但在可用时将重复使用以前构建的线程。
创建一个线程池,根据需要创建新线程,但在可用时将重复使用以前构建的线程。这些池通常会提高执行许多短寿命异步任务的程序的性能。如果可用,将重复使用以前构建的线程。如果没有可用的线程,将**创建一个新的线程并添加到池中。未使用 60 秒的线程被终止并从缓存中删除。**因此,闲置足够长的时间池不会消耗任何资源。请注意,具有类似属性但具有不同详细信息(例如超时参数)的池可能使用线程池执行器构造器创建。execute
// 创建一个线程池,根据需要创建新线程,但在可用时将重复使用以前构建的线程。
ExecutorService service = Executors.newCachedThreadPool();
Thread thread4 = new Thread(() -> {
System.out.println("我是一个线程");
});
FutureTask F= new FutureTask(new Callable() {
@Override
public Object call() throws Exception {
System.out.println("我也是一个线程");
return null;
}
});
service.submit(F);
service.submit(thread4);
System.out.println(thread4.getName());
service.shutdown();
之前在这里遇到过问题,所以也需要分析一下
分析------------>>>
static ExecutorService newCachedThreadPool(ThreadFactory threadFactory)
static ExecutorService newCachedThreadPool(ThreadFactory threadFactory)
创建一个线程池,根据需要创建新线程,但在可用时将重复使用以前构建的线程,并在需要时使用提供的线程工厂创建新线程。
简言之就是传入一个线程工厂并缓存起来
ExecutorService service1 = Executors.newCachedThreadPool(threadFactory);
Thread thread5 = threadFactory.newThread(() -> {
System.out.println("由线程工厂创建的线程缓冲池中的线程");
});
Thread thread6 = threadFactory.newThread(() -> {
System.out.println("由线程工厂创建的线程缓冲池中的线程");
});
service1.submit(thread5);
service1.submit(thread6);
System.out.println(thread5.getName());//pool-1-thread-3
System.out.println(thread6.getName());// pool-1-thread-4
service1.shutdown();
newCachedThreadPool的缺点
要了解它的缺点,就要看一下源码—>>
线程池的大小有一个范围 0,到Integer.MAX_VALUE,基本算是无界线程池了;然后他的阻塞队列用的是
1.直接向 SynchronousQueue 中提交任务
2.如果有空闲线程,就去取出任务执行;如果没有空闲线程,就新建一个
3.执行完任务的线程有 60 秒生存时间,如果在这个时间内可以接到新任务,就可以继续活下去,否则就拜拜,由于空闲 60 秒的线程会被终止,长时间保持空闲的 CachedThreadPool 不会占用任何资源。CachedThreadPool 用于并发执行大量短期的小任务,或者是负载较轻的服务器。
static ExecutorService newFixedThreadPool(int nThreads)
static ExecutorService newFixedThreadPool(int nThreads)
创建一个nThreads大小的线程池,该线程池可重复使用从共享的无限制队列中运行的固定数量的线程。在任何时候,大多数线程都将是主动处理任务。如果在所有线程处于活动状态时提交其他任务,则它们将在队列中等待,直到有线程可用。如果任何线程在关闭前执行**过程中因故障而终止,则如果执行后续任务需要,则将取代新线程。**池中的线程将存在,直到它被明确关闭。
简言之就是我这有一个池子,能容纳 nThreads个线程,当池子满了的时候先添加的线程进入等待,直到池子有空位置的时候,如果池子中的线程再关闭时因为故障而终止,新线程就会取而代之,除非仍然需要这个线程干活,这个线程才会留在池子里,直到它明确关闭
/* 创建一个nThreads大小的线程池,该线程池可重复使用从共享的无限制队列中运行的固定数量的线程。
在任何时候,大多数线程都将是主动处理任务。如果在所有线程处于活动状态时提交其他任务,
则它们将在队列中等待,直到有线程可用。如果任何线程在关闭前执行过程中因故障而终止,
则如果执行后续任务需要,则将取代新线程。池中的线程将存在,直到它被明确关闭。*/
ExecutorService service2 = Executors.newFixedThreadPool(1);
Thread thread7;
Thread thread8;
thread7 = new Thread(() -> {
for (int i = 10; i < 20; i++) {
}
System.out.println("我还留在线程池里吗?");
});
thread8 = new Thread(() -> {
for (int i = 0; i < 100; i++) {
}
System.out.println("我被执行了吗?");
});
service2.submit(thread7);
service2.submit(thread8);
service2.shutdown();
static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
创建一个线程池,该线程池可重复使用从共享的无限制队列中运行的固定数量的线程,使用提供的线程工厂在需要时创建新线程。
static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
创建一个线程池,该线程池可重复使用从共享的无限制队列中运行的固定数量的线程,使用提供的线程工厂在需要时创建新线程。
跟上面类似,这次是用自己指定的线程工厂创建线程
newFixedThreadPool的缺点—>>
静态方法------------>>>>返回值为ExecutorService
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
创建一个线程池,可以安排命令在给定延迟后运行,或定期执行。
corePoolSize- 要保留在池中的线程数,即使它们处于空闲状态
/* 可安排命令在给定延迟后运行或定期执行的执行者服务。
这些方法会产生各种延迟的任务,并返回可用于取消或检查执行的任务对象。
并且方法创建和执行定期运行直到取消的任务。schedulescheduleAtFixedRatescheduleWithFixedDelay
使用执行器.执行(可运行)和执行器服务方法提交的命令的延迟为零。
方法中还**允许零延迟和负延迟(但不允许延迟)**,并视为立即执行请求。*/
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
//可以传Runnable
ScheduledFuture<?> ai = scheduledExecutorService.schedule(() -> System.out.println("I love you"), 5, TimeUnit.SECONDS);//延迟为0或者负值则视为不延迟
//还可以传Callable
ScheduledFuture<String> schedule = scheduledExecutorService.schedule(() -> "我爱你中国", 2, TimeUnit.SECONDS);
System.out.println("定时任务的返回值"+schedule.get());
//除了执行一次性任务外,还可以执行多次任务
Runnable runnable=()->{
System.out.println("I LOVE YOU BABY");
};
//参数 ,要执行的线程,第一次执行延期的时间,连续执行之间的时间
ScheduledFuture<?> scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(runnable, 10, 1, TimeUnit.SECONDS);//初始执行延迟10秒,之后每隔一秒打印一句I LOVE YOU BABY
//scheduledExecutorService.shutdown();
System.out.println("------------------------Executors.newScheduledThreadPool(2, threadFactory1);----------------------------");
ScheduledExecutorService scheduledExecutorService1 = Executors.newScheduledThreadPool(2, threadFactory1);
Thread thread11 = threadFactory1.newThread(() -> {
System.out.println("五秒后提醒我玩游戏");
});
scheduledExecutorService1.schedule(thread11, 6, TimeUnit.SECONDS);
scheduledExecutorService1.shutdown();
简单研究一下scheduleAtFixedRate与scheduleWithFixedDelay
scheduleAtFixedRate
分为两种情况------------>>>>>>>>>>>>
第一种是如果任务执行的时间小于等于周期即设置的参数----period 那么就会按照周期设定值进行循环任务执行
//导包.....略
public class TestSchedule {
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
Runnable runnable=()->{
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("I LOVE YOU BABY");
};
scheduledExecutorService.scheduleAtFixedRate(runnable,1,1, TimeUnit.SECONDS);
}
}
//假设初始时间为0
//任务第一次执行 延迟1秒
//从开始到第一次执行时间 要延迟1秒,在到第一次执行完,总共花了initialDelay(初始延迟1秒)+ 执行时间(忽略不计,反正不超过1秒),执行时间不超过Period,下一个任务在上一个执行完毕之后1秒后开始执行,即各任务之间并不是并发任务
//第二次执行的时间为initialDelay(1秒)+ 第一次执行时间(忽略不计)=第2秒 开始, 第二次执行完后1秒又开始执行第三次
第二种是如果任务时间大于周期即设置的参数----period ,那么就会在等待上一个任务完成后立即执行下一个任务
public class TestSchedule {
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
Runnable runnable=()->{
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("I LOVE YOU BABY");
};
scheduledExecutorService.scheduleAtFixedRate(runnable,1,1, TimeUnit.SECONDS);
}
}
//依旧假设初始时间为0
//任务第一次执行延迟1秒,每隔1秒执行一次,但是一次任务需要5秒,
//开始到第一次执行时间延迟1秒,到第一次执行完 总共花了initialDelay(1秒)+ 执行时间(5秒),然 超过Period了,下一个线程等待等上一个线程结束后才开始立即执行, 即并不是并发任务
//第二次执行的时间为initialDelay(1秒)+ 第一次执行时间(5秒)=第六秒 开始,然后执行一次又花了5秒, 第二次执行完的时间 为第11秒
scheduleWithFixedDelay
也是分为两种情况讨论--------->>>>>>>
第一种任务执行时间小于等于延迟时间
public class TestSchedule {
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
Runnable runnable2=()->{
System.out.println("我爱你宝贝");
};
scheduledExecutorService.scheduleWithFixedDelay(runnable2,1,3,TimeUnit.SECONDS);
}
}
//依旧假设初始时间为0;
从开始到第一个任务执行 延迟1秒 第一秒
第一个任务开始到第一个任务结束 花费时间忽略不计
从第一个任务结束到第二个任务开始 花费 3秒 即第二个任务在第四秒时开始;
第二种情况是当任务执行时间大于延迟时间
public class TestSchedule {
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
Runnable runnable2=()->{
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我爱你宝贝");
};
scheduledExecutorService.scheduleWithFixedDelay(runnable2,1,3,TimeUnit.SECONDS);
}
}
依旧假设初始时间为0 第一次执行时 延迟 1秒, 第1秒
由于任务执行时间为5秒, 所以第一次执行时间结束为 第6秒,
等着第一次任务执行结束后 在延迟 3秒执行下一次任务, 第9秒
即每次任务结束到下一次任务开始之间间隔为 3秒 所以第二次执行开始的时间为 第 9秒,结束时间 第14秒,在等待三秒下一次任务才开始执行;
看一下源码吧!!!
ThreadPoolExecutor
public class ThreadPoolExecutor
extends AbstractExecutorService
案例代码—>>
package com.gavin;
import java.util.ArrayList;
import java.util.concurrent.*;
public class ThreadPoolDemo {
public static void main(String[] args) {
/* new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return null;
}
};*/
RejectedExecutionHandler rejectedExecutionHandler = (r, executor) -> {
if (executor.getTaskCount() >= 6) {
System.out.println("程序被终止");
System.exit(1);
}
};
BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable>(1);
//核心线程 2,最大线程数4 核心线程可超时2秒 ,超出最大线程进入阻塞队列 (可调阻塞队列大小)
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 4, 1, TimeUnit.SECONDS, blockingQueue,new ThreadPoolExecutor.CallerRunsPolicy());
ArrayList<Runnable> arrayList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
int finalI = i;
arrayList.add(() -> {
System.out.println("hello-world"+ finalI);
});
}
for (int i = 0; i < 10; i++) {
threadPoolExecutor.execute(arrayList.get(i));
}
}
}
核心和最大池大小
将根据corePoolSize和 maximumPoolSize设置的边界自动调整池大小,在提交新任务时,如果运行的线程小于核心线程数,则会创建一个新线程来处理请求,其他线程处于空闲状态也是要创建新线程的,如果运行的线程数小于最大值,也将创建一个新线程来处理
任何 BlockingQueue 都可用于传输和保留已提交的任务。此队列的使用与池大小调整交互:
如果运行的线程少于 corePoolSize 线程,则执行程序始终倾向于添加新线程而不是排队。
如果 corePoolSize 或更多线程正在运行,则执行程序始终倾向于对请求进行排队,而不是添加新线程。
如果请求无法排队,则会创建一个新线程,除非该线程超过 maxPoolSize,在这种情况下,任务将被拒绝。,
newSingleThreadExecutor
FinalizableDelegatedExecutorService–可中止的委托线程执行服务
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
newSingleThreadScheduledExecutor
提交一个定期操作,该操作在给定的初始延迟后首先启用,随后在给定的时间段内启用;也就是说,处决将在 之后开始,然后 ,然后,依此类推。initialDelayinitialDelay + periodinitialDelay + 2 * period
任务执行的顺序无限期地继续,直到发生以下异常完成之一:
该任务通过返回的未来显式取消。
执行程序终止,也会导致任务取消。
执行任务会引发异常。在这种情况下,在返回的未来调用 get 将抛出 ExecutionException,将异常作为其原因。
后续执行将被抑制。在返回的未来对 isDone() 的后续调用将返回 。true
如果执行此任务所需的时间超过其周期,则后续执行可能会延迟开始,但不会同时执行。
public static void Demo4(){
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleAtFixedRate(()->System.out.println("nihao"),10,10,TimeUnit.SECONDS);
// scheduledExecutorService.shutdown();
}