感谢作者无私奉献
http://www.cnblogs.com/sunddenly/p/4104180.html
多进程
- 多任务操作系统可以通过周期性地将CPU从一个进程切换到另一个进程,来实现同时运行多个进程。 尽管对于一个CPU而言,它在某个时间点只能运行一个进程,但CPU可以在多个进程之间进行轮换执行,并且CPU的切换速度极高,使我们无法感知其切换的过程,就好像有多个进程在同时执行。
- 进程是资源分配的最小单位,开辟新的进程也比较费资源。并发量不高
多线程
归纳起采可以这样说:操作系统可以同时执行多个任务,每个任务就是进程;进程可以同时执行多个任务,每个任务就是线程。简而言之,一个程序运行后至少有一个进程,一个进程里可以包含多个线程,但至少要包含一个线程。
线程与进程不同:
1. 进程之间不能共享内存,但线程之间共享内存非常容易
2. 线程在程序中是独立的、并发的执行流,与分隔的进程相比,进程中线程之间的隔离程度要小。
3. 系统创建进程时需要为该进程重新分配系统资源,但创建线程则代价小得多,因此使用多线程来实现多任务并发比多进程的效率高
4. Java语言内置了多线程功能支持,而不是单纯地作为底层操作系统的调度方式,从而简化了Java的多线程编程
生命周期
https://www.cnblogs.com/sunddenly/p/4106562.html
特别之处:
将周期与jvm的东西结合。
线程间的状态转换:
当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态。尤其是当线程启动以后,它不可能一直”霸占”着CPU独自运行,所以CPU需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换
线程周期中jvm的工作。
1. 新建状态,当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时仅由JVM为其分配内存,并初始化其成员变量的值
2. 就绪状态,当线程对象调用了start()方法之后,该线程处于就绪状态。Java虚拟机会为其创建方法调用栈和程序计数器,处于这个状态中的线程并没有开始运行,只是表示该线程可以运行了。至于该线程何时开始运行,取决于JVM里线程调度器的调度
3. 运行状态,如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态
4. 阻塞状态,当处于运行状态的线程失去所占用资源之后,便进入阻塞状态
5. 在线程的生命周期当中,线程的各种状态的转换过程
线程间的状态转换:
https://my.oschina.net/mingdongcheng/blog/139263
1. 新建(new):新创建了一个线程对象。
可运行(runnable):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。
运行(running):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。
阻塞(block):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况分三种:
(一). 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
(二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
(三). 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
- 死亡(dead):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
线程调度
- 抢占式调度策略
- 系统会给每个可执行的线程一个小时间段来处理任务;当该时间段用完后,系统就会剥夺该线程所占用的资源,让其他线程获得执行的机会。在选择下一个线程时,系统会考虑线程的优先级
- 协作式调度策略
- 所有现代的桌面和服务器操作系统都采用抢占式调度策略,但一些小型设备如手机则可能采用协作式调度策略,在这样的系统中,只有当一个线程调用了它的sleep()或yield()方法后才会放弃所占用的资源——也就是必须由该线程主动放弃所占用的资源
线程控制
摘要
Java的线程支持提供了一些便捷的工具方法,通过这些便捷的工具方法可以很好地控制线程的执行
- join线程控制,让一个线程等待另一个线程完成的方法
- 后台线程(守护线程)Daemon Thread,又称为守护线程或精灵线程。它的任务是为其他的线程提供服务,如果所有的前台线程都死亡,后台线程会自动死亡
- 线程睡眠sleep,让当前正在执行的线程暂停一段时,并进入阻塞状态
- 线程让步yield,让当前正在执行的线程暂停,但它不会阻塞该线程,它只是将该线程转入就绪状态
总结:sleep 与yield区别
- sleep()方法暂停当前线程后,会给其他线程执行机会,不会理会其他线程的优先级;但yield()方法只会给优先级相同,或优先级更高的线程执行机会
- sleep()方法会将线程转入阻塞状态,直到经过阻塞时间才会转入就绪状态:而yield()不会将线程转入阻塞状态,它只是强制当前线程进入就绪状态。因此完全有可能某个线程调用yield()方法暂停之后,立即再次获得处理器资源被执行
- sleep()方法声明抛出了InterruptcdException异常,所以调用sleep()方法时要么捕捉该异常,要么显式声明抛出该异常;而yield()方法则没有声明抛出任何异常
- sleep()方法比yield()方法有更好的可移植性,通常不建议使用yield()方法来控制并发线程的执行
总结:sleep 与wait区别
- sleep 释放资源,但不释放锁;wait释放资源,又释放锁。
- sleep是Thread类的方法,wait是Object类中定义的方法
- sleep显式抛出异常,wait没有
- 释放完cpu资源后
- sleep方法的线程进入阻塞,等时间到后,进入可执行状态;
- wait/notify方法的线程必须放在同步代码块或者同步方法中。
sychoronized(o){
t1.wait();//t1线程被放到了对象o的一个队列中,t1线程进入阻塞等其他线程t2调用o.notify/notifyAll方法时,进入可执行状态;o.notify会从对象o的那个队列中随机一个线程赋予锁
}