进程和线程的由来
操作系统的特征:并发,共享,虚拟,异步
任务处理方式的历程:串行 》》 批处理 》》 进程 》》 线程
注:
- 并行:同一时刻运行
- 并发:同一段时间内同时运行
引入进程是为了更好地使多道程序并发执行,提高资源利用率和系统吞吐量(增加并发程度)
引入线程的目的是为了减少程序在并发执行时付出的时空开销(提高并发性能)
进程
所有与进程相关的资源,被记录在PCB中
进程的特点
- 动态
- 并发
- 独立
- 异步
- 结构
进程的状态
三状态:创建,运行,结束
五状态(用的最多):就绪,阻塞,运行,创建,结束
七状态:就绪,阻塞,运行,创建,结束,就绪挂起,阻塞挂起
状态的转换
就绪——》运行:获得处理机资源
运行——》就绪:(1)时间片用尽,让出处理机(2)更高优先级的进程就绪
运行——》阻塞(主动):请求某一资源
阻塞——》就绪(被动):I/O结束或中断结束
线程
线程只由堆栈寄存器和程序计数器和TCB组成(没有自己的地址空间)
线程的实现可以分为:用户级线程(无TCB)和内核级线程(轻量级进程)
1 .内核级线程:切换由内核控制,当线程进行切换的时候,由用户态转化为内核态。切换完毕要从内核态返回用户态;可以很好的利用smp,即利用多核cpu。windows线程就是这样的。
- 用户级线程内核的切换由用户态程序自己控制内核切换,不需要内核干涉,少了进出内核态的消耗,但不能很好的利用多核Cpu,目前Linux pthread大体是这么做的。
操作系统进程和线程的区别
(1)进程是分配资源的最小单位,线程是CPU调度的最小单位
(2)进程是抢占处理机的调度单位,线程属于某个进程,共享其资源
(3)线程不能看作独立应用,进程可以看作独立应用
(4) 线程没有独立的地址空间,线程只是进程的不同执行路径(一个线程挂了,整个进程就挂了)
(5)进程的切换比线程的切换开销大
Java进程与线程的关系
- Java对操作系统提供的功能进行封装,包括进程和线程
- 运行一个程序会产生一个进程,进程至少包含一个线程】
- 每个进程对应一个JVM实例,多个线程共享JVM里面的堆
- java采用单线程编程模型,程序会自动创建主线程
- 主线程可以创建子线程,原则上要后于子线程完成
Thread中的run和start方法
调用start()会创建一个新的子线程并启动
run方法只是Thread的一个普通方法的调用,并未启动线程
Thread和Runnable的区别
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
4):线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类
线程实现的三种方法
Thread,Runnable,Callable
sleep和wait方法的区别
- sleep是Thread类的方法,wait是Object类中定义的方法
- sleep()方法可以在任何地方使用
- wait()方法只能在synchronized方法或synchronized块中使用
- Thread.sleep只会让出CPU,不会导致锁行为的改变,Object.wait不仅让出CPU,还会释放已经占有的同步资源锁(需要被唤醒)
notify和notifyall,yield,interrupt的区别
锁池
假设线程A已经拥有了某个对象的锁,线程B,C想获得该对象的一个synchronized方法,但是被A占用了,线程B,C阻塞,并会进入一个地方等待,这个地方叫锁池
等待池
假设线程A调用了某个对象的Wait()方法,线程A就会释放该对象的锁,同时线程A就进入到了该对象的等待池中,进入到等待池中的线程不会去竞争该对象的锁
- notifyAll会让所有处于等待池的线程全部进入锁池去竞争获取锁的机会
- notify只会随机选取一个处于等待池的线程进入锁池去竞争获取锁的机会
- 当调用Thread.yield()方法时,会给线程调度器一个当前线程愿意让出CPU使用的暗示,但是线程调度器可能会忽略这个提示
如何中断线程
- 通过stop()方法(已被放弃)
- 通过suspend()和resume()方法(已被放弃)
- interrupt(),通知线程应该被中断了
(1)如果线程处于被阻塞状态,那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常
(2)如果线程处于正常活动状态,那么会将该线程的中断标志设为true,被设置中断标志的线程将继续正常运行,不受影响