曾经古老的DOS操作系统是单任务的。还没有线程的概念,系统在每次仅仅能做一件事情。比方你在copy东西的时候不能rename文件名称。
为了提高系统的利用效率,採用批处理来批量运行任务。
如今的操作系统都是多任务操作系统,每一个执行的任务就是操作系统所做的一件事情。比方你在听歌的同一时候还在用MSN和好友聊天。
听歌和聊天就是两个任务。这个两个任务是“同一时候”进行的。一个任务一般相应一个进程。也可能包括好几个进程。
比方执行的MSN就相应一个MSN的进程。假设你用的是windows系统,你就能够在任务管理器中看到操作系统正在执行的进程信息。
一般来说,当运行一个应用程序的时候,就启动了一个进程,当然有些会启动多个进程。
比方QQ。你用QQ等多个账号的时候。打开任务管理器的时候就会发现打开一个账户就会有一个进程。启动进程的时候。操作系统会为进程分配资源。当中最基本的资源是内存空间。由于程序是在内存中运行的。
在进程中。有些程序流程块是能够乱序运行的。而且这个代码块能够同一时候被多次运行。实际上,这种代码块就是线程体。线程是进程中乱序运行的代码流程。当多个线程同一时候运行的时候,这种运行模式成为并发运行。当中一半会满足两个条件,一个是能够乱序运行。一个是会被多次运行。
多线程的目的是为了最大限度的利用CPU资源。
Java编敲代码都执行在在Java虚拟机(JVM)中,在JVM的内部,程序的多任务是通过线程来实现的。每用java命令启动一个java应用程序,就会启动一个JVM进程。
在同一个JVM进程中。有且仅仅有一个进程。就是它自己。在这个JVM环境中,全部程序代码的执行都是以线程来执行。
一般常见的Java应用程序都是单线程的。比方,用java命令执行一个最简单的HelloWorld的Java应用程序时,就启动了一个JVM进程。JVM找到程序程序的入口点main(),然后执行main()方法。这样就产生了一个线程,这个线程称之为主线程。
当然除了主线程之外肯定还会有另外的后台线程。比方肯定会有的垃圾回收线程。
当main方法结束后。主线程执行完毕,当前台线程,这里也就是主线程,其它后台线程也随之结束。JVM进程也随即退出 。
对于一个进程中的多个线程来说,多个线程共享进程的内存块,当有新的线程产生的时候,操作系统不分配新的内存,而是让新线程共享原有的进程块的内存。因此,线程间的通信非常easy,速度也非常快。不同的进程由于处于不同的内存块,因此进程之间的通信相对困难,为了保证其安全性和每一个账户各自不同属性。多个QQ账号是以多个进程而非多个线程来执行。但线程共享进程块的内存也带来另外一个问题。当对个进程訪问同一个类调用同样的方法和读写同样变量时可能会破坏数据。导致异常的情况。
在Java程序中,JVM负责线程的调度。线程调度是值依照特定的机制为多个线程分配CPU的使用权。
调度的模式有两种:分时调度和抢占式调度。
分时调度是全部线程轮流获得CPU使用权,并平均分配每一个线程占用CPU的时间。抢占式调度是依据线程的优先级别来获取CPU的使用权。
JVM的线程调度模式採用了抢占式模式。比方Main线程它的优先级就是5。你能够通过setPriority()函数来设置线程的优先级,从1到10,10优先级最高,1优先级最低,但不代表优先级高就一定先运行,谁先运行还是取决于谁先抢占CPU的资源,较高的优先级唯独有比較高的运行机会。JVM提供了10个线程优先级,但与常见的操作系统都不能非常好的映射。假设希望程序能移植到各个操作系统中,应该只使用Thread类有下面三个静态常量作为优先级,这样能保证相同的优先级採用了相同的调度方式。
所谓的“并发运行”、“同一时候”事实上都不是真正意义上的“同一时候”。
用我们操作系统老师的话说就是,宏观上并行。微观上串行。尽管操作系统是多线程多任务的,可是对于CPU来说。在同一时刻内,它仅仅能做一件事。
在一个时钟周期内。它就仅仅能运行一条命令(特殊情况会有多条)。操作系统将进程线程进行管理,轮流(没有固定的顺序)分配每一个进程非常短的一段是时间(不一定是均分),然后在每一个线程内部,程序代码自己处理该进程内部线程的时间分配,多个线程之间相互的切换去运行,这个切换时间也是非常短的。因此多任务、多进程、多线程都是操作系统给人的一种宏观感受,从微观角度看,程序的运行是异步运行的。
部分概念:
主线程:JVM调用程序mian()所产生的线程。
当前线程:这个是easy混淆的概念。一般指通过Thread.currentThread()来获取的进程。
后台线程:指为其它线程提供服务的线程,也称为守护线程。JVM的垃圾回收线程就是一个后台线程。
前台线程:是指接受后台线程服务的线程,事实上前台后台线程是联系在一起,就像傀儡和幕后操纵者一样的关系。
傀儡是前台线程、幕后操纵者是后台线程。由前台线程创建的线程默认也是前台线程。能够通过isDaemon()和setDaemon()方法来推断和设置一个线程是否为后台线程。