线程是什么?
回答这个问题之前,我们首先需要了解进程。因为线程是在进程中运行的。
进程:是操作系统调度的最小单元。当一个进程内没有线程时,这个进程就会被销毁。也就是说如果一个进程存活状态,那么它至少拥有>=1个线程。
线程:是CPU调度(CPU时间片轮转机制)的最小单元,他必须依托于进程。
拓展: CPU核心数和线程数关系。一般情况下是1:1(线程数 = cpu个数 * 核数),现在基本都采用超线程技术达到1:2(线程数 = cpu个数 * 2*核数)
CPU时间片轮转机制:
根据先进先出原则,排成队列(就绪队列),调度时,将CPU分配给队首进程,让其执行一个时间段(称为:时间片),时间片通常为10-100ms数量级,当执行的时间片用完时,会由计时器发出时钟中断请求,调度程序便据此来停止该进程的执行,并将它排到队列末尾,然后再把CPU重新分配给当前队列的队首进程,同理如此往复。
并发和并行:
并行:同一时刻多个任务一起执行的任务,这些任务执行状态就是并行的。(同时的)
并发:在某一个时间段内,任务的执行量(吞吐量)。因为CPU的时间片轮转机制,可以让CPU在一定时间内交替执行不同任务。 (不是同时的)。并发大大提高了任务的处理效率,但是并发要与实际情况相结合,不能让CPU过累,因为CPU在随机切换的时候也会消耗资源,线程的创建也会消耗资源,一次性创建过多的线程会直接让CPU执行变慢,资源溢出等问题。
其实我们程序绝大多数情况都是并发多线程执行的。比如当你CPU到达100%的时候,你依旧有机会能够杀死。
JAVA中线程的调度:主要包含两种:抢占式线程调度器和协作式线程调度器。(所有的Java虚拟机都有一个线程调度器,用来确定哪个时刻运行哪个线程。)
抢占式线程调度: 每个线程可能会有自己的优先级,但是优先及并不意味着高优先级的线程一定会被调度,而是由CPU随机的选择,所谓抢占式的线程调度,就是说一个线程在执行自己的任务时,虽然任务还没有执行完,但是CPU会迫使它暂停,让其它线程占有CPU的使用权。(线程不能决定自身能够执行完,由CPU决定)(java虚拟机采用抢占式调度模型)
协作式线程调度: 每个线程可以有自己的优先级,但优先级并不意味着高优先级的线程一定会被最先调度,而是由cpu时机选择的,所谓协作式的线程调度,就是说一个线程在执行自己的任务时,不允许被中途打断,一定等当前线程将任务执行完毕后才会释放对cpu的占有,其它线程才可以抢占该cpu。(线程执行完后,CPU才会调度其他线程)
Java在调度机制上采用的是抢占式的线程调度机制。
Java线程在运行的过程中多个线程之间是协作式的。
线程的启动方式
本质上2种方式,Thread实现Runnable接口或者自己实现Runnable接口,实际有3种方式:
无参有2种形式:
①内部实现Runnable接口。
②实现Runnable接口。
实现Runnable接口带参数返回:本质上是实现Runnable接口
(Callable、Future和FutureTask)阻塞式返回结果常见问题:
Thread .run()和.start()的区别?
run()是函数调用,Thread实现的Runnable接口。作为普通方法调用,既然是普通方法,那么就是在当前线程顺序执行,并没有一开启一个新线程。(普通方法)
start(),让线程启动进入准备就绪(准备被执行状态)。等待CPU调度然后执行run方法,这是多线程。(启动线程)
Thread.join():创建线程,并立马获取到执行权,调用run()执行。
Thread.sleep():线程挂起进入阻塞状态,挂起一段时间后进入准备就绪状态。sleep可能会抛出InterruptedException异常。
Thread.wait()、notify()、notifyAll():需在持有锁机制下使用。详见后续。
Thread.yield():让出当前执行权,一般不会使用到这个方法。
Thread的各个方法调用的意义和作用。
我们大致可以用一张图来解释。
任何暴力的中断线程均会导致线程中资源得不到很好的回收,正确的中断方式是让线程run()执行结束后回收线程。线程的中断。
有3种方式:
①run方法内内置标志位,让run运行结束
②stop,不推荐使用,且已过期。
③interrupt()异常法。
Thread 提供interrupt()方法,内置一个Booean变量记录中断状态。
interrupt()方法仅仅是在当前线程中打了一个停止的标识将中断标志修改为true,并没有真正的停止线程。如果在此基础上进入堵塞状态(sleep(),wait(),join()),马上就会抛出一个InterruptedException,且中断标志被清除,重新设置为false,线程退出。
即interrupt()+能够让线程进入堵塞状态的方法(其中有3种方法能够让线程进入堵塞状态:sleep(),wait(),join()),其中join是其他线程调用,抢占线程执行权达到堵塞目的。
interrupt只是内置的一个boolean变量。我们可以自行定义变量一样可以达到中断的效果。最终实现目的都是让线程run()执行结束。
网友评论