2.Thread类
将Runnable对象转变为工作任务的传统方式是把他提交给一个Thread构造器,如下
public class BasicThreads {
public static void main(String[] args) {
Thread thread=new Thread(new Liftoff());
thread.start();
System.out.println("waiting ofr LiftOff");
}
}/* out
waiting ofr LiftOff
#0(9), #0(8), #0(7), #0(6), #0(5), #0(4), #0(3), #0(2),
#0(1), #0(Liftoff!),
*/
详细分析这段代码
Thread构造器只需要一个Runnable对象。Thread对象的start()方法为该线程执行必需的初始化操作,然后调用Runnable的run()方法,这时可以看见main方法的waiting Liftoff也执行,因为LiftOff.run中的方法和main是不同线程执行,接下来我们来添加更多的线程驱动
public class MoreBasicThread {
public static void main(String[] args) {
for(int i=0;i<5;i++){
new Thread(new Liftoff()).start();
}
System.out.println("waiting for LiftOff");
}
}/*out
waiting for LiftOff
#4(9), #1(9), #2(9), #0(9), #2(8), #1(8), #3(9), #4(8), #3(8), #1(7), #2(7), #0(8), #2(6), #1(6), #3(7), #4(7), #3(6), #1(5), #2(5), #0(7), #2(4), #1(4), #3(5), #4(6), #3(4), #1(3), #2(3), #0(6), #2(2), #1(2), #3(3), #4(5), #3(2), #1(1), #2(1), #0(5), #0(4), #0(3), #0(2), #0(1), #0(Liftoff!), #2(Liftoff!), #1(Liftoff!), #3(1), #4(4), #3(Liftoff!), #4(3), #4(2), #4(1), #4(Liftoff!),
*/
对于代码中我们添加了一个for循环启动了5个线程,对于输出中我们可以看见不同人物的执行的线程被换进换出时混在一起。这种交换是由线程调度器自动控制的,如果在你的处理器上有多个处理器,线程调度器将会在这些处理器之间默默地分发线程。
这个结果的输出每次并不是相同,线程的调度机制是非确定性的。
3.EXecutor
think in java中说Executor在java SE5/6中是启动任务的优选方法。
在这里我查询了一下相关资料在7和8里面也是优选的方法
public interface Executor {
void execute(Runnable command);
}
上面是这个接口的定义。
我们可以在第二节里面显示创建Thread对象代替。
thin in java没有讲其好处写得详尽,让我开始觉得并没有好大的作用,这里详细分析这个好处。
- 第一个好处也是think in java书上提到的将客户端和任务执行分开,这点就是命令模式,将任务的提交过程和执行过程解耦
- 第二个好处也是最重要的好处:我们使用Thread中创建大量线程时,会把线程创建语句随意地散落在代码中,无法统一管理线程的数量,而过量的线程创建将直接使系统崩溃,他和Executor不同Executor从线程池中提取线程,通过重用现有的线程而不是一味的创建新县城。可以在处理多个请求时分摊在线程创建和销毁过程中产生巨大的开销。
现在讨论Executor的使用
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CachedThreadPool {
public static void main(String[] args) {
ExecutorService executorService=Executors.newCachedThreadPool();
for(int i=0;i<5;i++){
executorService.execute(new Liftoff());
}
executorService.shutdown();
}
}/*Out
#0(9), #4(9), #2(9), #1(9), #3(9), #1(8), #2(8), #3(8), #4(8), #4(7), #1(7), #0(8), #1(6), #4(6), #3(7), #2(7), #3(6), #4(5), #1(5), #0(7), #3(5), #4(4), #3(4), #4(3), #2(6), #4(2), #3(3), #4(1), #1(4), #4(Liftoff!), #0(6), #0(5), #1(3), #3(2), #2(5), #3(1), #1(2), #1(1), #1(Liftoff!), #0(4), #3(Liftoff!), #2(4), #0(3), #2(3), #0(2), #2(2), #0(1), #2(1), #0(Liftoff!), #2(Liftoff!), */
这里我们使用ExecutorService(具有生命周期的Executor:运行,关闭,终止)ExecutorService在初始化创建时处于运行状态。shutdown方法将执行平缓的关闭过程:不在接受新任务,同事等待已经提交的任务执行完成(包括哪些还未开始执行的任务)。shutdownNow方法将执行粗暴的关闭过程:将把所有的任务(不管你在执行还是没有执行)全部取消。
这里对newCachedThreadPool进行分析:
除了newCachedThreadPool之外还有FixedThreadPool和SingleThreadExecutor进行分析。
newCachedThreadPool:newCachedThreadPool将创建一个可缓存的线程池,如果线程池的当前规模超过了处理需求,那么将回收空闲线程;而当需求增加时,可以添加新的线程,线程池的规模不存在任何限制。
newFixedThreadPool:newFixedThreadPool将创建一个固定大小的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程池的规模将不再变化;
newSingleThreadExecutor:newSingleThreadExecutor是一个单线程的Executor,它创建单个工作者线程执行任务,如果这个线程异常结束,会创建另一个线程代替。