1.参考:https://blog.csdn.net/qq_27378875/article/details/81610696
https://blog.csdn.net/chenfengdejuanlian/article/details/54969339
https://blog.csdn.net/axi295309066/article/details/65665090
Java并发工具包java.util.concurrent用户指南中英文对照阅读版.pdf
http://tutorials.jenkov.com/java-concurrency/index.html(java指南)
https://blog.csdn.net/suyongcai1234/article/details/106762789
http://www.voidcn.com/search/oozixd
https://www.jb51.net/article/184834.htm
http://ddrv.cn/a/25602
2.介绍:JDK1.5之前,java处理并发问题只能用悲观锁(synchronized),悲观锁需要考虑:性能、死锁、公平性、资源管理以及如何避免线程安全性方面带来的危害等问题,之后Sun大神(Doug Lea)就引进了java.util.concurrent工具类。
3.java.util.concurrent的重要模块:执行器的概念和线程池的实现。Executor、ExecutorService框架,Callable、Future,原子类(java.util.concurrent.atomic),锁机制,并发容器类和其它工具类
4.执行器服务(ExecutorService)
(1)说明:java.util.concurrent.ExecutorService 接口是一个异步执行机制,是一个线程池实现。
(2)工作原理示例:
例子:
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});
executorService.shutdown();
总结:
1.使用 newFixedThreadPool() 工厂方法创建一个 ExecutorService实例,并设置线程池的线程数,这里设置了十个。
2.将一个 Runnable 接口的匿名实现类传递给 execute() 方法。让ExecutorService 中的某个线程执行该 Runnable。
(3)任务委派(异步执行机制)
图解:
方法:
(1)execute(Runnable)
execute(Runnable) 方法要求一个 java.lang.Runnable 对象,然后对它进行异步执行。以下是
使用 ExecutorService 执行一个 Runnable 的示例:
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});
executorService.shutdown();
注:没有办法得知被执行的 Runnable 的执行结果
(2)submit(Runnable)
submit(Runnable) 方法也要求一个 Runnable 实现类,但它返回一个 Future 对象。这个
Future 对象可以用来检查 Runnable 是否已经执行完毕。
以下是 ExecutorService submit() 示例:
Future future = executorService.submit(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});
future.get(); //returns null if the task has finished correctly.
(3)submit(Callable)
submit(Callable) 方法类似于 submit(Runnable) 方法,除了它所要求的参数类型之外。
Callable 实例除了它的 call() 方法能够返回一个结果之外和一个 Runnable 很相像。
Runnable.run() 不能够返回一个结果。
Callable 的结果可以通过 submit(Callable) 方法返回的 Future 对象进行获取。以下是一个
ExecutorService Callable 示例:
Future future = executorService.submit(new Callable(){
public Object call() throws Exception {
System.out.println("Asynchronous Callable");
return "Callable Result";
}
});
System.out.println("future.get() = " + future.get());
以上代码输出:
Asynchronous Callable
future.get() = Callable Result
(4)invokeAny()
invokeAny() 方法实现一系列的 Callable 或者其子接口的实例对象。
注:1.调用这个方法并不会返回一个 Future,但它返回其中一个 Callable 对象的结果。无法保证返回的是哪个 Callable的结果 - 只能表明其中一个已执行结束。
2.如果其中一个任务执行结束(或者抛了一个异常),其他 Callable 将被取消。
示例:
ExecutorService executorService = Executors.newSingleThreadExecutor();
Set<Callable<String>> callables = new HashSet<Callable<String>>();
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 1";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 2";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 3";
}
});
String result = executorService.invokeAny(callables);
System.out.println("result = " + result);
executorService.shutdown();
总结:多次尝试返回的结果都不一样,说明其返回的是随机一个Callable的结果返回,也说明executorService线程池中并没有设置线程的优先顺序,随机执行一个线程
(5)invokeAll()
invokeAll() 方法将调用你在集合中传给 ExecutorService 的所有 Callable 对象。
注:1.invokeAll()返回一系列的 Future 对象,通过它们你可以获取每个 Callable 的执行结果。
2.一个任务可能会由于一个异常而结束,因此它可能没有 "成功"。无法通过一个 Future对象来告知我们是两种结束中的哪一种。(这段实际用到记得下吧,不是太明白含义,可能就是说异常捕捉不处理吧)
示例:
ExecutorService executorService = Executors.newSingleThreadExecutor();
Set<Callable<String>> callables = new HashSet<Callable<String>>();
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 1";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 2";
}
});
callables.add(new Callable<String>() {
public String call() throws Exception {
return "Task 3";
}
});
List<Future<String>> futures = executorService.invokeAll(callables);
for(Future<String> future : futures){
System.out.println("future.get = " + future.get());
}
executorService.shutdown();
(6) 关闭线程
使用完 ExecutorService 之后你应该将其关闭,以使其中的线程不再运行。
比如,如果你的应用是通过一个 main() 方法启动的,之后 main 方法退出了你的应用,如果你的应用有一个活动的 ExexutorService 它将还会保持运行。ExecutorService 里的活动线程阻止了 JVM 的关闭。
方法:executorService.shutdown();
注:1.调用 ExecutorService 的 shutdown() 方法,ExecutorService 并不会立即关闭,但它将不再接受新的任务,而且一旦所有线程都完成了当前任务的时候,ExecutorService 将会关闭。
在 shutdown() 被调用之前所有提交给ExecutorService 的任务都被执行。
2.想要立即关闭 ExecutorService,你可以调用 shutdownNow() 方法。这样会立即尝试停止所有执行中的任务,并忽略掉那些已提交但尚未开始处理的任务。无法担保执行任务的正确执行。可能它们被停止了,也可能已经执行结束。
注:该线程将任务委派给 ExecutorService,该线程将继续它自己的执行,独立于该任务的执行。
(4)ExecutorService是接口,具体的实现类如下:
ExecutorService executorService1 = Executors.newSingleThreadExecutor();
ExecutorService executorService2 = Executors.newFixedThreadPool(10);
ExecutorService executorService3 = Executors.newScheduledThreadPool(10);
5.线程池执行者 ThreadPoolExecutor(是执行器服务(ExecutorService)接口的实现类,本来想放在一起看的,但发现执行服务器用封装的class(Executors)给封装了,这算是线程池的封装吧,所以觉得还是分开说说)
了解: (1)java.util.concurrent.ThreadPoolExecutor 是 ExecutorService 接 口 的 一 个 实 现 。
(2)ThreadPoolExecutor 使用其内部池中的线程执行给定任务(Callable 或者 Runnable)。--是主线程(线程池)调用子线程(Callable或者Runnable),委派任务,异步执行机构
(3) 设置线程池数量:corePoolSize(至少有多少个线程在执行),maximumPoolSize(最大的线程数)
(4)示例:
int corePoolSize = 5;
int maxPoolSize = 10;
long keepAliveTime = 5000;
ExecutorService threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maxPoolSize,keepAliveTime,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
6.定时执行者服务ScheduledExecutorService(是执行器服务(ExecutorService)接口的实现类,本来想放在一起看的,但发现执行服务器用封装的class(Executors)给封装了,这算是线程池的封装吧,所以觉得还是分开说说)
(1) 介绍:java.util.concurrent.ScheduledExecutorService 是一个 ExecutorService,
它能够将任务延后执行,或者间隔固定时间多次执行。 任务由一个工作者线程异步执行,而不是由提交任务给ScheduledExecutorService 的那个线程执行。
(2)示例:
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
ScheduledFuture scheduledFuture =scheduledExecutorService.schedule(new Callable() {
public Object call() throws Exception {
System.out.println("Executed!");
return "Called!";
}
},
5,
TimeUnit.SECONDS);--执行时间按秒算
过程:首先一个内置 5 个线程的 ScheduledExecutorService 被创建。之后一个 Callable 接口的匿名类示例被创建然后传递给 schedule() 方法。后边的俩参数定义了 Callable 将在 5 秒钟之后被执行。
(3) 常用的方法(这里必须的明白一个坑,执行器服务(ExecutorService)前面介绍的都不是加了定时任务的)
schedule (Callable task, long delay, TimeUnit timeunit)
schedule (Runnable task, long delay, TimeUnit timeunit)
scheduleAtFixedRate (Runnable, long initialDelay, long period, TimeUnit timeunit)
scheduleWithFixedDelay (Runnable, long initialDelay, long period, TimeUnit timeunit)
(4)常用的方法说明:
1.schedule (Callable task, long delay, TimeUnit timeunit)
介绍:这个方法计划指定的 Callable 在给定的延迟之后执行。这个方法返回一个 ScheduledFuture,通过它你可以在它被执行之前对它进行取消,或者在它执行之后获取结果。
例子:
ScheduledExecutorService scheduledExecutorService =Executors.newScheduledThreadPool(5);
ScheduledFuture scheduledFuture =scheduledExecutorService.schedule(new Callable() {
public Object call() throws Exception {
System.out.println("Executed!");
return "Called!";
}
},
5,TimeUnit.SECONDS);
System.out.println("result = " + scheduledFuture.get());
scheduledExecutorService.shutdown();
2.schedule (Runnable task, long delay, TimeUnit timeunit) --和Callable差不多但不会返回结果,告知线程是否执行成功
3.scheduleAtFixedRate (Runnable, long initialDelay, long period, TimeUnit timeunit)
该任务将会在首个 initialDelay 之后得到执行,然后每个 period 时间之后重复执行。
如果给定任务的执行抛出了异常,该任务将不再执行。如果没有任何异常的话,这个任务将会持续循环执行到 ScheduledExecutorService 被关闭。
如果一个任务占用了比计划的时间间隔更长的时候,
下一次执行将在当前执行结束执行才开始。计划任务在
同一时间不会有多个线程同时执行。
4.scheduleWithFixedDelay (Runnable, long initialDelay,long period, TimeUnit timeunit)
(1)除了 period 有不同的解释之外这个方法和 scheduleAtFixedRate() 非常像。
(2)scheduleAtFixedRate() 方法中,period 被解释为前一个执行的开始和下一个执行的开始之间的间隔时间。
(3)scheduleWithFixedDelay()方法中,period 则被解释为前一个执行的结束和下一个执行的结束之间的间隔。因此这个延迟是执行结束之间的间隔,而不是执行开始之间的间隔。
(4)总结下:scheduleAtFixedRate和scheduleWithFixedDelay这两个别管时间间隔算得是啥,你还是当成重复的执行定时任务