基本概念
并发与并行
并发:指两个或多个事件在同一个时间段内发生
并行:指两个或多个事件在同一时刻发生(同时发生)
进程与线程
进程是正在运行的程序的实例。进程是线程的容器,即一个进程中可以开启多个线程
线程是进程内部的一个独立执行单元。一个进程可以同时并发运行多个线程
创建线程
继承Thread
(1)优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程
(2)缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类实现Runnable接口
(1)优点:线程类只是实现了Runnable接口,还可以继承其他的类。在这种方式下,可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况。
(2)缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。实现Callable接口
(1)具有Runnable的优缺点
(2)可以抛出受检查的异常
(3)可以调用Future.cancel取消执行
(4)支持返回执行结果,需要调用FutureTask.get()方法实现。此方法会阻塞主线程直到获取结果线程池
Executor –> ExecutorService –> AbstractExecutorService –> ThreadPoolExecutor –> ScheduledThreadPoolExecutorExecutor –> ExecutorService –> ScheduledExecutorService –> ScheduledThreadPoolExecutor
executorService.execute(Runnable()实现类) executorService.submit(Callable()实现类)
线程生命周期
新建
- new关键字创建了一个线程之后,该线程就处于新建状态
- JVM为线程分配内存,初始化成员变量值
就绪
- 当线程对象调用了start()方法之后,该线程处于就绪状态
- JVM为线程创建方法栈和程序计数器,等待线程调度器调度
就绪
- 就绪状态的线程获得CPU资源,开始运行run()方法,该线程进入运行状态
阻塞
- 线程调用sleep()方法主动放弃所占用的处理器资源
- 线程调用了一个阻塞式IO方法,在该方法返回之前,该线程被阻塞
- 线程试图获得一个同步锁(同步监视器),但该同步锁正被其他线程所持有
- 线程在等待某个通知(notify)
- 程序调用了线程的suspend()方法将该线程挂起。但这个方法容易导致死锁,所以应该尽量避免使用该方法
死亡
- run()或call()方法执行完成,线程正常结束
- 线程抛出一个未捕获的Exception或Error
- 调用该线程stop()方法来结束该线程,该方法容易导致死锁,不推荐使用
线程死锁
死锁的必要条件有4个,互斥、不可剥夺、请求与保持、循环等待
互斥:在一段时间内某资源仅为一个进程所占有,其他进程只能等待
不可剥夺:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,只能主动释放
请求与保持:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放
循环等待:循环等待链中每一个进程已获得的资源同时被链中下一个进程所请求
文档信息
- 本文作者:Weikang Yu
- 本文链接:https://AccelYu.github.io/2020/04/01/thread_basic/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)