进程与线程
进程是系统进行资源分配和调度的基本单位,一个进程可以包括多个线程
线程是是CPU调度和分派的基本单位,是比进程更小的能独立运行的基本单位
进程与线程的区别
线程不能看作独立应用,而进行可以看作独立应用
进程有独立的地址空间,相互不影响,线程只是进程的不同执行路径
线程没有独立的地址空间,多进程程序比多线程程序更加健壮
进程的切换比线程的切换开销更大
进程与线程的关系(Java)
Java对操作系统提供的功能进行封装,包括进程和线程
运行一个程序会产生一个进程,进程包含至少一个线程
每个进程对应一个JVM实例,多个线程共享JVM里的堆
Java采用单线程编程模型,程序会自动创建主线程
主线程可以创建子线程,原则上要后于自线程完成执行
start和run方法
- 调用start方法会创建一个新的自线程并启动
- run方法只是Thread的一个普通方法的调用
Thread和Runnable
- Thread是实现Runnable接口的类,使得run支持多线程
- 因为类的单一继承原则,推荐多使用Runnable接口
如何给run方法传参数
- 构造函数传参数
- 成员变量传参数
- 回掉函数传参数
如何实现线程的返回值
- 主线程等待法
- 使用Thread类的join阻塞当前线程等待子线程处理完毕
- 通过Callable接口实现,通过FutureTask Or 线程池获取
线程的状态
- 新建:创建后尚未启动的线程的状态
- 运行:包含Ready和Running
- 无限期等待:不会被分配CPU时间片,需要被显式唤醒。如:没有设置Timeout参数的Object.wait()方法,没有设置参数的的Thread.join()方法,LockSupport.park()方法
- 限期等待:在一段时间后会由系统自动唤醒
- 阻塞:等待获取排它锁
- 结束:已经终止的线程的状态
sleep和wait
基本差别
- sleep是Thread类的方法,wait是Object的方法
- sleep方法可以在任何地方调用
- wait方法只能在synchronized方法或者synchronized块中调用
本质区别
- Thread.sleep()只会让出cpu,不会让出锁
- Object.wait不仅会让出CPU,还会释放已经占用的同步资源锁
notify和notifyAll
锁池
假设线程A已经拥有了某个对象的锁,而其他线程B想要调用这个对象的某个synchronized方法(或者块),由于线程B在进入对象的synchronized方法(或者块)之前必须先获得该对象锁的拥有权,而恰巧该对象的锁目前正在被A占用,此时B线程就会被阻塞,进入一个地方去等待锁的释放,这个地方便是该对象的锁池
等待池
假设线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁,同时线程A就进入到了该对象的等待池中,进入到等待池中的线程不会去竞争该对象的锁
notify和notifyAll的区别
- notifyAll会让所有处于等待池的线程全部进入锁池去竞争获取锁的机会
- notify只会随机选取一个处于等待池中的线程进入锁池去竞争获取锁的机会
yield
当调用Thread.yield()函数时,会给线程调度器一个当前线程愿意让出CPU使用的暗示,但是线程调度器可能会忽略这个暗示。yield只会让出cpu资源(愿意让,并不少一定让),但是不会影响锁
如何中断线程
调用interrupt(),通知线程应该中断了
- 如果线程处于被阻塞状态,那么线程将立即退出阻塞状态并抛出InterruptedException异常
- 如果线程处于正常活动状态,那么会将线程将的中断标志设置成true。被设置中断标志的线程将继续正常运行,不受影响