Java高并发基础篇:并发与线程(一)

2018-10-09  本文已影响17人  浆水鱼鱼哈

0x01、你必须知道线程是什么?

线程是轻量级进程,是程序执行的最小单位

在介绍线程之前,我们必须要知道进程的概念。进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。进程是程序的基本执行体,线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。

进程和线程是什么关系?

进程是线程的容器,一个进程可以容纳若干个线程。

我们可以把进程比喻成一个工厂的车间,线程就是车间里每个流水线上的工人,车间里的设备就是进程内的资源,工人在各自的流水线上使用设备生产,就像线程各自占用进程里的资源执行任务一样。

0x02线程的生命周期或状态

线程状态图

线程的所有状态在Thread中的State枚举中定义:

public enum State {
        NEW,
        RUNNABLE,
        BLOCKED,
        WAITING,
        TIMED_WAITING,
        TERMINATED;
    }

注意:从NEW状态触发后,线程不能再回到NEW状态,同理,处于TERMINATED的线程也不能再回到RUNNABLE状态。

0x03并发的几个概念

同步(Synchronous)和异步(Asynchronous)

临界区

临界区用来表示一种公共资源或者说是共享数据,可以被多个线程使用。但一次只能由一个线程来使用它,其他线程想要使用,必须等待。
在并行程序中,临界区资源是保护的对象。

阻塞(Blocking)和非阻塞(Non-Blocking)

阻塞和非阻塞通常用来形容多线程间的相互影响。当一个线程占用了临界区资源,其他需要这个资源的线程必须在临界区等待。等待会导致线程挂起,这种情况就是阻塞。
非阻塞,强调没有一个线程可以妨碍其他线程的执行。

死锁(Deadlock)、饥饿(Starvation)和活锁(Livelock)

死锁、饥饿和活锁都属于多线程的活跃性问题,如果出现上述几种情况,那么相关线程可能就不再活跃,也就很难再继续执行下去。

产生死锁的四个必要条件:

(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。


循环等待导致死锁产生

0x04并发级别

由于临界区的存在,多线程之间的并发必须受到控制。根据并发的策略,可以把并发的级别进行分类,可分为阻塞、无饥饿、无障碍、无锁、无等待几种。

阻塞(Blocking)

一个线程是阻塞的,那么在其他线程释放资源之前(即当前线程未得到临界区的锁),当前线程无法继续执行(挂起等待)。使用synchronized关键字和重入锁得到的就是阻塞的线程。

无饥饿(Starvation-Free)

如果线程之间是有优先级的,那么线程调度的时候总是会倾向于满足高优先级的线程。也就是说,对于同一资源的分配是不公平的。这种非公平的锁来说,系统允许优先级高的线程插队。就可能会导致低优先级的线程产生饥饿。

无障碍(Obstruction-Free)

无障碍是一种最弱的非阻塞调度。无障碍执行不会因为临界区的问题导致一方被挂起,任何线程都可以进入临界区,修改共享数据。对于无障碍的线程来说,一旦检测到多方同时修改共享数据的情况,它会立即对自己所做的修改进行回滚,确保数据安全。

无锁(Lock-Free)

无锁的并行都是无障碍的,所有线程都能尝试对临界区进行访问。

无等待(Wait-Free)

无等待是一种在无锁的基础上更进一步进行扩展,它要求所有线程都必须在有限步内完成,这样就不会引起饥饿问题。

0x05并发的原子性、可见性和有序性

上一篇下一篇

猜你喜欢

热点阅读