parent
c70cd6491d
commit
f5f8ffd074
@ -0,0 +1,45 @@ |
|||||||
|
--- |
||||||
|
并发相关口水话 |
||||||
|
--- |
||||||
|
|
||||||
|
#### 目录 |
||||||
|
|
||||||
|
1. 进程和线程的区别? |
||||||
|
2. 创建线程的方式? |
||||||
|
3. 线程的生命周期? |
||||||
|
4. 一些 Object、Thread 方法的理解? |
||||||
|
1. wait、notify/notifyAll 等待通知机制 |
||||||
|
2. Thread 的 sleep、join、yield 和线程中断 |
||||||
|
5. 线程死锁 |
||||||
|
|
||||||
|
#### 进程和线程区别? |
||||||
|
|
||||||
|
进程是操作系统资源分配的基本单位,而线程是 CPU 调度和分配的基本单位。进程有独立的地址空间,一个进程崩溃后在保护模式下不会对其他进程产生影响,而线程只是一个进程中的不同的执行路径,所以也可以说进程是执行的程序,线程是进程内不同的执行控制流。当然,进程是执行的程序,这是一种非正式的说法,进程不只是程序代码,进程还包括当前活动,如进程堆栈和数据段等等。 |
||||||
|
|
||||||
|
操作系统内的每个进程表示,采用进程控制块 PCB,它包含很多和进程相关的信息,如进程状态、CPU 寄存器、CPU 调度信息等等。而线程也有一个 TCB 线程控制块表示,它包括线程 ID、程序计数器、堆栈等等。 |
||||||
|
|
||||||
|
#### 创建线程的方式? |
||||||
|
|
||||||
|
创建线程有两种方式,一种是直接 new Thread 重写它的 run 方法,还有一种是实现 Runnable 接口传给 Thread。这两种方式都是没法获取任务执行结果的,如果需要获取任务执行结果,就需要使用到了 FutureTask。而且因为历史设计的原因,Thread 只接受 Runnable 而不接受 Callable,而 FutureTask 就是是 Runnable 和 Callable 的包装,本身是继承 Runnable 的,所以可以直接传给 Thread,调用其 get 方法就可以获取到执行结果,如果任务没有执行完,无参 get 就会一直阻塞,当然也可以使用 超时 get,超过一定时间就返回 null。 |
||||||
|
|
||||||
|
#### 线程的生命周期? |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### 一些 Object、Thread 方法的理解? |
||||||
|
|
||||||
|
首先就是线程的等待通知机制,等待通知机制设计到了两个函数 wait 和 notify/notifyAll,它们就是 Object 的方法,wait 函数是当一个线程调用了共享变量的 wait 方法时,该调用线程就会被阻塞挂起,直到其他线程调用了该共享变量的 notify/notifyAll 方法唤醒。需要注意的是,调用 wait 方法的线程需要先获取该对象的监视器锁,不然就会抛出 IllegalMonitorStateException,那么如何获取一个共享变量的监视器锁呢?其实就是加 synchronzied 即可。调用 wait 方法会释放当前共享变量的监视器锁,不然就会死锁了。wait 还有一个超时重载函数,如果在指定时间没有被唤醒就直接返回了,无参 wait 调用的其实就 wait(0) 方法。调用 notify 函数是随机唤醒一个等待线程,而 notifyAll 就是唤醒所有等待线程。同 wait 一致,只有获取了共享变量的监视器锁后,才可以调用其 notify/notifyAll 方法。 |
||||||
|
|
||||||
|
还有等待线程执行完成的 join 方法,以及让线程休眠的 sleep 方法,sleep 方法和 wait 方法不同的是,sleep 并不会释放锁。Object#wait、Thread#join、Thread#sleep 在阻塞期间,其他线程调用了该线程的 interrupt 方法中断线程,都会抛出 InterruptedException。 |
||||||
|
|
||||||
|
其次就是让出 CPU 执行权的 Thread#yield 方法,让线程调度器进行下一轮的线程调度,不过需要注意的是,下一轮调度的时候也有可能会再次调度到自己。yield 方法一般是用在自旋中。 |
||||||
|
|
||||||
|
最后就是线程中断了,线程中断是一种线程间的协作模式,通过设置线程的中断标志并不能直接中断线程的执行,而是被中断的线程根据中断状态自行处理。现在中断包括两个函数,一个 interrupt() 方法,中断线程,还有一个是 Thread 的静态方法 interrupted 方法,前者不会清楚标志位,后者会清除标志位。 |
||||||
|
|
||||||
|
#### 线程死锁 |
||||||
|
|
||||||
|
死锁是指两个或多个线程在执行过程中,因争夺资源而造成的一直相互等待而无法继续运行下去。 |
||||||
|
|
||||||
|
死锁产生的条件必须具备以下四个条件:互斥条件、请求并持有、不可剥脱和环路等待。想要避免死锁,只需要破坏掉至少一个构成死锁的条件即可,但是目前只有请求并持有和环路等待条件是可以被破坏的。造成死锁的原因其实和申请资源的顺序有很大关系,使用资源申请的有序性原则就可以避免死锁。 |
||||||
|
|
||||||
|
然后比较滑稽的是,现代操作处理死锁的办法是直接忽视。虽然看起来这似乎不是一个解决死锁问题的可行办法,但是确实大多数操作系统所采用的,代价是一个重要的考虑因素,对于许多系统,死锁很少发生(如一年一次),发生死锁就直接人工重启了。使用频繁的死锁预防、死锁避免和死锁检测与恢复相比,这种办法更便宜。 |
Loading…
Reference in new issue