java在JDK1.5之后引入了并发计算框架,java.util.concurrent。这个框架大大减轻了简化了多线程的开发工作。一个线程大概有五种状态:新建状态(New)、可运行状态(Runnable,也叫做运行状态)、阻塞状态(Blocked)、等待状态(Waiting)、结束状态(Terminated)。线程的状态只能由新建转变为了运行状态后才能被阻塞或者等待状态。线程的状态流转如图所示:
注意:这里把等待状态给细分了一下。把等待状态分为了等待池和等锁池。
线程的运行时间可以分为三个部分:线程启动时间(T1),线程体的运行时间(T2),线程销毁时间(T3)。如果一个线程不能被重复使用,每次创建一个线程都要经过启动、运行、销毁这三个过程,这样就会增大系统的响应时间。那么有没有什么办法来降低系统的运行时间呢?答案就是使用线程池。 在系统启动的时候,我们先创建一定数量的线程放到线程池里。当需要时直接从线程池中获得线程,当运行完的时候,再把线程返回到线程池中。ExecutorService是实现了线程池的执行器。我们先来看一个线程池的小例子: package com.zkn.newlearn.thread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * Created by wb-zhangkenan on 2016/11/4. */ public class ThreadTestExecutors01 { public static void main(String[] args) { //创建一个两个线程的线程池 ExecutorService executors = Executors.newFixedThreadPool(2); for (int i = 0; i < 4; i++) { executors.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }); } executors.shutdown(); } } 本次代码执行了4遍线程体,按照之前我们说的一个线程不可能从结束状态转变为可运行状态,那为什么此处的2个线程可以反复使用呢?下面我们先简单的说一下线程的工作原理: 线程池的实现涉及以下三个名词: 1)工作线程(Worker) 线程池中的线程,只有两个状态:可运行状态和等待状态。在没有任务时它们处于等待状态,运行时可以循环的执行任务。 2)任务接口(Task) 这是每个任务必须实现的接口,以供工作线程调度器调度。它主要规定了任务的入口、任务执行完的场景处理、任务的执行状态等。这里有两种类型的任务:具有返回值(或异常)的Calleble接口任务和无返回值并兼容旧版本的Runnable接口任务。 3)任务队列(Work Queue) 也叫作工作队列,用于存放等待处理的任务。一般是BlockingQueue的实现类。用来实现任务的排队处理。 我们首先从线程池的创建说起,我们可以创建这几种类型的线程池。 1)、newSingleThreadExecutor:单线程池。 创建方式为:Executors.newSingleThreadExecutors(); 单线程池是一个池中只有一个线程在运行,该线程永不超时,而且由于是一个线程,当有多个任务需要处理时,会将他们放置到一个无界阻塞队列中逐个处理。 2)、newCachedThreadPool:缓冲功能的线程池 创建方式为:Executors.newCachedThreadPool(); 建立了一个线程池,而且线程数量是没有限制的(不能超过Integer的最大值),新增一个任务即有一个线程处理,或者复用之前空闲的线程,或者启动一个新的线程,但是一旦一个线程在60秒内一直是处于等待状态,则会被终止。 3)、newFixedThreadPool:固定线程数量的线程池 在初始化的时候,就已经决定了线程的最大数量。若任务添加的能力超出了线程的处理能力,则建立阻塞队列容纳多余的任务。 4)、newScheduledThreadPool:固定数量的定时或者周期性执行任务的线程池 创建方式为:Executors.newScheduledThreadPool() 用来存放定时或者周期性执行的任务的线程池。 还有其他的一些线程池,在用到的时候慢慢添加。在以后的文章中我会来根据源码来分析一下这四种线程池的创建和运行:
相关资源:敏捷开发V1.0.pptx