java中线程的一些相关概念,第3篇(主线程、线程优先级、线程组、精灵线程(守护线程)、线程状态、线程同步、死锁、线程间的通信)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/czh500/article/details/88741020

java中线程的一些相关概念,第3篇,看我这篇文章前,先看我上两篇

先了解一点线程相关的概念:主线程、线程优先级、线程组、精灵线程(守护线程)、线程状态、线程同步、死锁、线程间的通信(使用 wait()notify()notifyAll()进行线程间通信)

本文章资料和内容来自于网络的电子书,我觉得那本电子书写的挺好,挺通俗易懂的!感谢那本电子书的原作者!

我根据电子书上的案例,自己模仿着敲了一遍代码(详细的代码案例看我下一篇文章),感觉该电子书上的案例非常通俗易懂,案例很生活化,比较好理解,再次感谢电子书的原作者!

以下是电子书原作者的内容,版权归电子书原作者所有!

总结复习,需要背诵

理论:程序,进程与线程
程序:是对数据描述和操作代码的集合,是应用程序执行的脚本,它是静态的。
进程:是程序的一次执行过程,是系统运行程序的基本单位,进程是动态的
线程:是程序中相对独立的代码段,比进程更小的运行单位,多个线程构成一个进程,
线程也是动态的
从 dos 到 windows 有两个飞跃,一个 dos 是基于命令行的,而 windows 是基于 GUI(图
形用户界面的);第二个是 dos 是基于单任务的操作系统,而 windows 是基于多任务的。多
任务的两种实现:基于进程与基于线程。

虚拟的 CPU:封装在 Thread 类中,内部多为 native(本地)方法,这些本地方法负责
与操作系统交互,完成你多线程的功能。
线程体:。我们把覆盖的 run()方法称为线程体。
启动线程:这里我们通过调用 start()方法来启动线程。
理论:实现 Runnable 接口
当要实现多线程机制的类已经有了父类,可以让他实现 Runnable 接口,它是一个单方
法接口,同时 Thread 类也实现了该接口。
即便是您实现多线程机制的类可以继承 Thread,但仍建议实现 Runnable 接口,这样对
代码侵入性较小,可以提高程序的维护性,更不会改变类体系结构功能。

理论:主线程

主线程的重要性体现在两方面:它是产生其他子线程的线程,通常它必须最后完成执
行,因为它执行各种关闭动作。Thread.currentThread()静态方法是得到的是当前正
在运行的线程。

理论:线程优先级

Java 将线程的优先级分为 10 个等级,默认为 5(NORM_PRIORITY)对于高优先级,
java 使用优先执行的抢占式策略,而对于同优先级的线程使用先进先出的队列,使用时间片策略。

理论:线程组

所有线程都隶属于某个线程组,默认的为系统线程组,我们也可以在创建时设定它隶属
的线程组。线程组也必须从属于其他线程组。必须在构建器里指定新线程组从属于哪个线程
组。若在创建一个线程组的时候没有指定它的归属,则同样会自动成为系统线程组的一名属
下。因此,一个应用程序中的所有线程包括线程组最终会成为以系统线程组为根节点的一棵
树。
通过 getThreadGroup()方法得到当前线程隶属的线程组,线程组的 activeCount
方法得到当前线程中活动的线程和线程组数目

理论:守护线程

守护线程或者精灵线程通常在后台运行,是给用户线程提供支持服务的,它的特点是当
程序中没有用户线程在运行时,它就停止执行。通过 Thread 类的 setDaemon(boolean on)方
法把线程设置为守护线程,它必须在 start()方法之前调用。垃圾回收车也是一个守护线程,并
且垃圾回收线程的优先级最低为 1。

理论:线程状态

我们把线程生命周期的各个阶段称为线程的状态。线程的状态主要有新建,就绪,运
行,阻塞,死亡五种:

创建状态:更没有 CPU 时间资源,但有自己的内存空间。

就绪状态:调用 start()方法进入。已经具备了运行的条件,但还没分配到 CPU 资源,
只是进入了线程队列。

运行状态:运行状态的线程已经得到 CPU 的资源,拥有对 CPU 的控制权。会顺序执行自
己 run()方法中的代码,直到或调用其他方法终止,或等待某资源而阻塞,或完成任务
而死亡。

阻塞状态:进入运行状态的线程在某些情况下让出 CPU 并暂时终止自己的运行,进入阻
塞状态。引起阻塞的原因是调用了 Thread 的 sleep(毫秒)方法或等待 I/O 设备等资源
等。在阻塞状态下的线程不能进入就绪队列,只有当睡眠时间已到或等待的 I/O 设备空
闲等引起阻塞的原因消除后才能重新进入就绪对列。当再次获得 CPU 时,从原来终止的
位置开始继续运行。

死亡状态:这是线程生命周期的最后一个阶段,表示线程已经退出运行状态,并且不再
进入就绪队列。当线程的 run()方法结束或由于其他原因被终止后,线程进入消亡状
态。线程的终止分两种情况:自然死亡,即线程体执行结束;使用了 Thread 类的
destroy()或 stop()方法终止(java 不建议使用这两个方法,因为如还没释放资源,有

可能造成程序的死锁,死锁我们后面讨论)。
那线程的状态也可以用下图表示:

理论:线程同步

线程同步是为了保证当多个线程同时并发访问某资源时,在任何指定时间只有一个线程
可以访问该资源,从而使该资源的数据保持一致。

其中同步又分为同步方法和同步块。我们先看同步方法,同步方法的实现很简单,只要
在方法的声明前面加上 synchronized 关键字就可以。它的原理是在任何时刻一个对象中只
有一个同步方法可以执行。只有对象当前执行的同步方法结束后,同一个对象的另一个同步
方法才可能开始。这里的思想是,保证每个线程在调用对象同步方法时以独占的方法操作该

对象

线程同步的粒度越小越好,即线程同步的代码块越小越好。这时我们可以使用同步块。
因为同步块后面需要传递同步的对象参数,所以它可以指定更多的对象享受同步的优势,而
不像同步方法那样只有包含相关代码的对象受益。

Vector,Hashtable,StringBuffer 的方法是同步的,它们是线程安全的,而
ArrayList,HashMap,StringBuilder 是线程非安全的。对于单线程程序,您根本没必要使用
线程安全的类,那样反而会影响我们的程序运行效率。

理论:死锁

简单的所死锁发生的原因是第一个线程等待第二个线程释放资源,而第二个线程有等待
第一个线程释放资源。导致死锁的根源是不恰当的使用了同步方法,并且程序的运行轨迹没
经过严密的考虑。发生死锁一般要满足四个条件:
5. 互斥条件:一个资源每次只能被一个线程使用。
6. 请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不变。
7. 不剥夺条件:线程已获得的资源,在未使用完成前,不能强行剥夺。
8. 循环等待条件:若干线程之间形成一种头尾相连的循环等待资源关系。
我们还要知道,java 本身既不能预防死锁,也不能发现死锁,但理解的死锁的原因,尤
其是产生死锁的四个必要条件,那我们在系统设计,线程调度方面就可以谨慎对待来避免死
锁的发生。

理论:使用 wait()notify()notifyAll()进行线程间通信

线程间通信是让当前锁定某对象的线程在线程体没执行完的情况下解锁,让其它的线程
有机会执行刚才被锁定的同步方法,当然执行完后要通知以前的线程继续执行。
线程间通信主要使用 Object 类提供的三个方法:wait(),notify()与 notifyAll()来实
现。
wait():等待方法,可以让当前线程放弃监视器并进入睡眠状态,直到其它线程进入同
一监视器并调用 notify()或 notifyAll()方法。
notify():唤醒方法。可唤醒同一对象监视器中调用了 wait()方法的第一个线程。
notifyAll():唤醒所有线程的方法。唤醒同一对象监视器中调用了 wait()方法的所有线
程,具有最高优先级的线程首先被唤醒。

猜你喜欢

转载自blog.csdn.net/czh500/article/details/88741020