一、线程
1、线程实现方式
1.1、继承 Thread
public class Thread01 extends Thread{public static void main(String[] args) {Thread01 thread01 = new Thread01();thread01.start();}@Overridepublic void run() { System.out.println("继承Thread"); }}
Thread 类是实现 Runnable 这个接口类,由于Runnable 类中只有一个 run 方法,所以 Thread 要复写run方法,当我继承Thread类时要自己实现run方法,不然就是调用 Runnable的run方法,里面空空如也。如同 Bean 类要复写toString方法一样。

1.2、实现 Runnable
public class Runable01 implements Runnable{public static void main(String[] args) {Runable01 runable01 = new Runable01();new Thread(new Runable01()).start();}@Overridepublic void run() {System.out.println("实现Runnable");}}
当我们自己实现 Runnable 类时,需要把实现类对象放在 Thread 中 new 才能启动。
1.3、实现 Callable(有返回值)
import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;public class Callable01 implements Callable<String> {@Overridepublic String call() throws Exception { return "实现Callable"; }public static void main(String[] args) throws ExecutionException, InterruptedException {FutureTask task= new FutureTask(new Callable01());new Thread(task).start();System.out.println(task.get());}}
前面的 run 方法都是没有返回值的,但是 Callable 类中的 run 方法则可以返参,但是需要 FutureTask 类对其去接收,FT 类也是需要 run 方法。Callabel 类中有一个call 的泛型方法。
2、线程生命周期和状态

在 Thread 类代码中有一个State的枚举类,存放了6种java线程的状态。
中文解释:
3、线程的执行顺序
线程的执行顺序是随机的,就是线程 start 之后会进入运行等待状态,等待 cpu 时间分片。想要线程顺序执行需要使用 join()方法或者锁方法等。关于 join()方法,该方法中是用到 Object 中的 native 类型的 wait()方法,join()方法让主线程放弃 cpu 让给其他线程执行,等线程结束之后再让给 main 拿到 cpu。

join的意思是使得放弃当前线程的执行,并返回对应的线程,例如下面代码的意思就是: 程序在main线程中调用thread1线程的join方法,则main线程放弃cpu控制权,并返回thread1线程继续执行直到线程thread1执行完毕 所以结果是thread1线程执行完后,才到主线程执行,相当于在main线程中同步thread1线程,thread1执行完了,main线程才有执行的机会。
_
4、Thread、Runnable、Callable
4.1、实现 Runnable 接口相比继承 Thread 类的优势:
A、避免由于 Java 的单继承特性而带来的局限;
B、增强程序的健壮性,代码能够被多个线程共享,代码与数据是独立的;
C、线程池只能放入实现 Runable 或 Callable 类线程,不能直接放入继承 Thread 的类。
4.2、实现 Runnable 接口和实现 Callable 接口的区别
A、Runnable 是自从 Java1.1 就有了,而 Callable 是 1.5 之后才加上去的;
B、实现 Callable 接口的任务线程能返回执行结果,而实现 Runnable 接口的任务线程不能返回结果;
C、Callable 接口的call()方法允许抛异常,而 Runnable 接口的 run()方法异常只能在内部消化,不能继续上抛;
D、加入线程池运行,Runnable 使用 ExecutorService 的 execute 方法,Callable 使用 submit 方法。
注:Callable 接口支持返回执行结果,此时需要调用 FutureTask.get()方法实现,此方法会阻塞主线程直到获取返回结果,当不调用此方法时,主线程不会阻塞。
二、线程池

1、java 线程池
线程池有六种,常用四种:
- newCachedThreadPool
- newFixedThreadPool
- newSingleThreadExecutor
- newScheduleThreadPool
newSingleThreadScheduleExecutornewWorkStealingPool
ExecutorService执行器的 Java 2种基础线程池选择:定时线程池(ScheduleThreadPoolExecutor)和普通线程池(ThreadPoolExecutor)。
2、熟悉源码
public class ThreadPoolTest {public static void main(String[] args) {ExecutorService executorService = Executors.newCachedThreadPool();executorService.submit(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName());System.out.println("线程池示例");}});executorService.shutdown();}}
2.1、ThreadPoolExecutor#ThreadPoolExecutor
java.util.concurrent.ThreadPoolExecutor#ThreadPoolExecutor(
int,
int,
long,
java.util.concurrent.TimeUnit,
java.util.concurrent.BlockingQueue
java.util.concurrent.ThreadFactory,
java.util.concurrent.RejectedExecutionHandler
)
上面 demo 的第三行代码会使用到 ThreadPoolExecutor 类,java.util.concurrent.ThreadPoolExecutor
ThreadPoolExecutor的5个内部类:
1、DiscardPolicy
2、CallerRunsPolicy
3、Abortpolicy
4、DiscardOldestPolicy
5、Worker

ThreadPoolExecutor 的5个内部类可分两种类型:policy(策略)、worker(工作),先看下该类的构造函数:
• corePoolSize :池中所保存的线程数,包括空闲线程
• maximumPoolSize:池中允许的最大线程数
• keepAliveTime: 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间
• unit:keepAliveTime 参数的时间单位
• workQueue :执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务
• threadFactory:执行程序创建新线程时使用的工厂
• handler :由于超出线程范围和队列容量而使执行
2.2、AbstractExecutorService#submit
java.util.concurrent.AbstractExecutorService#submit(java.lang.Runnable)
关于 AbstractExecutorService 类,它是一个抽象类,它实现了接口类的 ExecutorService 类。关于 demo 的第四行代码中的 submit 方法,调用了 ExecutorService#submit,但是实际是 AbstractExecutorService#submit 方法,其代码如下:
2.3、ThreadPoolExecutor#execute
在上面的 submit 方法中,调用的 execute 方法,java.util.concurrent.ThreadPoolExecutor#execute,代码如下:
首先拿到当前状态的数量,数量就是线程池的 size,核心是能提供的数。
A:数量当小于核心:addWorker,往队列里放(创建新线程执行任务);
B:当大于核心:调用 BlockingQueue#offer(E)方法,类似list的add方法,<阻塞队列>;
C:当A和B都不符合时,直接增加task,用addWorker;
D:当C增加失败,调用ThreadPoolExecutor#reject 拒绝策略。
下面看一下在1367行中调用了 addWorker方法。
2.4、ThreadPoolExecutor#addWorker
代码如下:
代码中创建了 Work 对象去操作,该类在 ThreadPoolExecutor 中,它继承了 AbstractQueuedSynchronizer 这个同步器类,实现了 Runnable 类。当然这也就要复写 run 方法了,下图红框中 run 方法调用了 runWorker 方法。
2.5、ThreadPoolExecutor#runWorker
在 runWorker 方法中,用到了 getTask 方法。
2.6、ThreadPoolExecutor#getTask
看一下 workQueue,这是等待队列,它的poll和take方法,类似list的get,获取队列中的 task。
拿到task(这是线程)之后接着回到2.5中1149行代码,执行 run()方法,这个run方法就是我们 demo中自己复写的run 方法了;run 方法结束之后在2.5中会执行1167行的 processWorkerExit 方法,这个方法也调用了 addWorker方法。
最后demo的调用流程如下图所示:
3、execute 四种处理方式


A、当前池大小 poolSize < corePoolSize ,则把任务放到核心线程池中执行;
B、当前池大小 poolSize > corePoolSize ,且等待队列未满,则把任务放进等待队列中,然后由别人拿等待队列中任务到核心线程池中去执行;
C、当前池大小 poolSize > corePoolSize 且 < maximumPoolSize ,且等待队列已满,则创建非核心线程池,把任务放到里面去执行;
D、当前池大小 poolSize > corePoolSize 且 > maximumPoolSize ,且等待队列已满就调用拒绝策略处理任务。
线程池里的每个线程执行完任务后不会立刻退出,而是会去检查下等待队列里是否还有线程任务需要执行,
如果在 keepAliveTime 里等不到新的任务了,那么线程就会退出。
4、拒绝策略
线程池有四种拒绝策略:
AbortPolicy:抛出异常,默认;
CallerRunsPolicy:不使用线程池执行;
DiscardPolicy:直接丢弃任务;
DiscardOldestPolicy:丢弃队列中最旧的任务。
对于线程池选择的拒绝策略可以通过
RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy(); 来设置。
