是一个具备必定独立功能的程序在一个数据集上的一次动态执行的过程,是操做系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。java
线程是操做系统可以进行运算调度的最小单位。git
它被包含在进程之中,是进程中的实际运做单位。github
一条线程指的是进程中一个单一顺序的控制流,一个进程中能够并发多个线程,每条线程并行执行不一样的任务。面试
进程和线程的主要差异在于它们是不一样的操做系统资源管理方式。数组
进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响。安全
线程只是一个进程中的不一样执行路径。线程有本身的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,因此多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。网络
但对于一些要求同时进行而且又要共享某些变量的并发操做,只能用线程,不能用进程。数据结构
单线程程序:程序执行过程当中只有一个有效操做的序列,不一样操做之间都有明确的执行前后顺序,容易出现代码阻塞多线程
多线程程序:有多个线程,线程间独立运行,能有效地避免代码阻塞,而且提升程序的运行性能架构
(1)使用多线程能够减小程序的响应时间。 在单线程的状况下,若是某个程序很耗时或者陷入长时间等待(如等待网络响应),此时程序将不会相应鼠标和键盘等操做,使用多线程后,能够把这个耗时的线程分配到一个单独的线程去执行,从而是程序具有了更好的交互性。
(2)与进程相比,线程的建立和切换开销更小。 因为启动一个新的线程必须给这个线程分配独立的地址空间,创建许多数据结构来维护线程代码段、数据段等信息,而运行于同一个进程内的线程共享代码段、数据段,线程的启动或切换的开销就比进程要少不少。同时多线程在数据共享方面效率很是高。
(3)多CPU或多核心计算机自己就具备执行多线程的能力。 若是使用单个线程,将没法重复利用计算机资源,形成资源的巨大浪费。所以在多CPU计算机上使用多线程能提升CPU的利用率。
(4)使用多线程能简化程序的结构,使用程序便于理解和维护。 一个很是复杂的进程能够分红多个线程来执行。
当多个线程访问同一个对象时,若是不用考虑这些线程在运行时环境下的调度和交替运行,也不须要进行额外的同步,或者在调用方进行任何其余的协调操做,调用这个对象的行为均可以获取正确的结果,那这个对象是线程安全的。 ——<<深刻Java虚拟机>>
Java容许多线程并发控制,当多个线程同时操做一个可共享的资源变量时(如数据的增删改查),将会致使数据不许确,相互之间产生冲突。
所以加入同步锁以免在该线程没有完成操做以前,被其余线程的调用,从而保证了该变量的惟一性和准确性。
检查数值、改变数值,以及可能发生的睡眠操做均做为单一的、不可分割的原子操做完成。
二、进程间的内部数据和状态都是相互彻底独立的,所以进程间通讯大多数状况是必须经过网络实现。线程自己的数据,一般只有寄存器数据,以及一个程序执行时使用的堆栈,因此线程的切换比进程切换的负担要小。
三、CPU对于各个线程的调度是随机的(分时调度),在Java程序中,JVM负责线程的调度。 线程调度是指按照特定的机制为多个线程分配CPU的使用权,也就是实际执行的时候是线程,所以CPU调度的最小单位是线程,而资源分配的最小单位是进程。
栈:在函数中定义的基本类型的变量和对象的引用变量都是在函数的栈内存中分配。
堆:堆内存用于存放由new建立的对象和数组。
从通俗化的角度来讲,堆是用来存放对象的,栈是用来存放执行程序的
-Xss参数用来控制线程的堆栈大小。
当两个线程竞争同一资源时,若是对资源的访问顺序敏感,就称存在竞态条件。
在临界区中使用适当的同步就能够避免竞态条件。
界区实现方法有两种,一种是用synchronized,一种是用Lock显式锁实现。
不可变的对象必定是线程安全的,而且永远也不须要额外的同步。
Java类库中大多数基本数值类如Integer、String和BigInteger都是不可变的。
由类的规格说明所规定的约束在对象被多个线程访问时仍然有效,无论运行时环境如何排列,线程都不须要任何额外的同步。
如 Random 、ConcurrentHashMap、Concurrent集合、atomic
有条件的线程安全类对于单独的操做能够是线程安全的,可是某些操做序列可能须要外部同步。
有条件线程安全的最多见的例子是遍历由 Hashtable 或者 Vector 或者返回的迭代器
线程兼容类不是线程安全的,可是能够经过正确使用同步而在并发环境中安全地使用。
如ArrayList HashMap
线程对立是那些无论是否采用了同步措施,都不能在多线程环境中并发使用的代码。
如如System.setOut()、System.runFinalizersOnExit()
每个线程都是有优先级的,通常来讲,高优先级的线程在运行时会具备优先权,但这依赖于线程调度的实现,这个实现是和操做系统相关的(OSdependent)。
能够定义线程的优先级,可是这并不能保证高优先级的线程会在低优先级的线程前执行。线程优先级是一个int变量(从1-10),1表明最低优先级,10表明最高优先级。
线程调度器是一个操做系统服务,它负责为Runnable状态的线程分配CPU时间。一旦建立一个线程并启动它,它的执行便依赖于线程调度器的实现。
时间分片是指将可用的CPU时间分配给可用的Runnable线程的过程。分配CPU时间能够基于线程优先级或者线程等待的时间。
线程调度并不受到Java虚拟机控制,因此由应用程序来控制它是更好的选择。
单核CPU也支持多线程执行代码,CPU经过给每一个线程分配CPU时间片来实现这个机制。时间片是CPU分配给各个线程的时间,由于时间片很是短,因此CPU经过不停地切换线程执行,让咱们感受多个线程时同时执行的,时间片通常是几十毫秒(ms)。
操做系统中,CPU时间分片切换到另外一个就绪的线程,则须要保存当前线程的运行的位置,同时须要加载须要恢复线程的环境信息。
守护线程都是为JVM中全部非守护线程的运行提供便利服务: 只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就所有工做;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工做。
User和Daemon二者几乎没有区别,惟一的不一样之处就在于虚拟机的离开:若是 User Thread已经所有退出运行了,只剩下Daemon Thread存在了,虚拟机也就退出了。
由于没有了被守护者,Daemon也就没有工做可作了,也就没有继续运行程序的必要了。
任何线程均可以设置为守护线程和用户线程,经过方法Thread.setDaemon(bool on);true则把该线程设置为守护线程,反之则为用户线程。Thread.setDaemon()必须在Thread.start()以前调用,不然运行时会抛出异常。
守护线程至关于后台管理者 好比 : 进行内存回收,垃圾清理等工做
一、新建状态(New):新建立了一个线程对象。
二、就绪状态(Runnable):线程对象建立后,其余线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
三、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
四、阻塞状态(Blocked):阻塞状态是线程由于某种缘由放弃CPU使用权,暂时中止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的状况分三种: (一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。(wait会释放持有的锁) (二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。 (三)、其余阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程从新转入就绪状态。(注意,sleep是不会释放持有的锁)
五、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
Java提供的终止方法只有一个stop,可是不建议使用此方法,由于它有如下三个问题:
原文:Java架构笔记
免费Java高级资料须要本身领取,涵盖了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高并发分布式等教程,一共30G。
传送门: https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q