并发基本概念

一、基本概念

1、并发与并行

  • 并发:在单个处理器上采用单核执行多个任务即为并发。
  • 并行:同一时间在不同的计算机、处理器或者处理核心上同时运行多个任务。

2、同步

  • 一种协调两个或者更多任务以获得预期结果的机制
  • 控制同步:第二个任务依赖于第一个任务的结束时,只能在第一个任务结束之后执行
  • 数据访问同步:同一时间只能有一个任务访问共享变量
  • 临界段:用来访问共享资源的一段代码

3、不可变对象

  • 在初始化后不能修改其属性的对象,比如 String.class

4、原子操作和原子变量

  • 原子操作是不会被线程调度机制打断的操作,一旦开始就会运行到结束,可以通过一个临界段来实现
  • 原子变量:原子操作的基本单位。可以使用某种同步机制,或者 CAS以无锁方式来实现。

5、任务通信方法

  • 共享内存:通常用于在一台计算机上运行多任务的情况。对共享内存的访问必须用同步机制的临界段完成。
  • 消息传递:通常用于在不同计算机上运行多任务的情形。发送消息,保持阻塞并等待响应则是同步。发送消息后继续执行则为异步。

二、并应用程序中可能出现的问题

1、数据竞争

在没有同步机制下,多个任务同时操作一个共享变量,会出现错误。

2、死锁

当多个任务等待某个线程释放资源,而该线程又在等待其他线程释放资源时,并发应用程序就会出现死锁。

3、活锁

当系统中两个任务总是因对方的行为而改变自己状态,就出现了活锁。会使他们进入状态变更的死循环而无法继续执行。

4、资源不足

当某个任务在系统中无法获取维持其继续执行所需要的资源时,就会出现资源不足。

  • 如果系统中没有设计良好的算法,那么系统中有些线程很可能要为获取该资源而等待很长时间

5、优先权反转

当一个低优先权的任务持有了一个高优先级任务的所需的资源时,就会发生优先权反转,这样低级的就会在高级之前执行

三、设计并发算法的方法论

1、先从算法的串行版本开始设计,用于检查并发算法是否生成了正确的结果,以及是否能够改善响应时间

2、通过循环排查,分析串行版本中哪部分花费过多

3、使用两种方法进行设:

  • 任务分解:将代码划分成多个独立的任务。当任务按照顺序或者同时进行时,需要用同步机制进行处理
  • 数据分解:多个任务对数据集的一个子集进行处理。对共享资源必须用临界段来保护。
  • 粒度过细会引入更多代码,导致性能下降
  • 粒度过粗会导致资源浪费

4、实现测试调整

5、设计需要考虑的方面:效率、简单、可移植性、可扩展性

四、Java 并发 API

1、基本并发类:

  • Thread 类: 描述了执行并发 Java 应用程序的所有线程
  • Runnable接口:这是 Java 中创建并发应用程序的一种方式
  • ThreadLocal 类:该类用于存放从属于某一线程的变量
  • ThreadFactory 接口:这是实现 Factory 设计模式的基类,可以用来创建定制线程

2、同步机制:

  • synchronized关键字:允许你在某个代码块或者某个完整的方法中定义一个临界段
  • Lock 接口:比 synchronized 更为灵活。
    • ReentrantLock用于实现一个可以与某种条件相关联的锁
    • ReentrantReadLock将读写操作分离开来
    • StampedLock是 Java8新增的,包括三种控制读、写访问的模式
  • CountDownLatch类:该类允许一个任务等待多项操作的结束
  • CyclicBarrier类:该类允许多线程在某一共同点上进行同步
  • Phaser类:该类允许你控制那些分割成多个阶段的任务的执行。在所有任务都完成当前阶段之前,任何任务都不能进入下一阶段

这些同步机制可以支持你:

  • 定义用于访问某一共享资源的临界段
  • 在某一共同点上同步不同的任务

3、执行器

执行器可以将线程的创建和管理分开。不必担心线程的创建和管理,只需要关心任务的创建,并将其发送给执行器。

  • Executor接口和ExecutorService接口:包含了执行器共有的execute()方法
  • ThreadPoolExecutor类: 该类允许你获取一个含有线程池的执行器,而且可以定义并行任务的最大数
  • ScheduledThreadPoolExecutor类:这是一种特殊的执行器,可以使你在某段延迟之后执行或者周期性执行
  • Executors类:该类使执行器的创建更为容易
  • Callable接口:这是 Runnable 接口的替代接口,可以有返回值
  • Future接口:该接口包含了一些能获取 Callbel 接口返回值并控制其状态的方法

4、Fork/Join 框架

是一种特殊的执行器,是为细粒度处理而存在的,针对采用分治方法进行求解的问题。

  • ForkJoinPool:该类实现了主要用于运行任务的执行器
  • ForkJoinTask:这是一个可以在 ForkJoinPool类中执行的任务
  • ForkJoinWorkerThread:这是一个准备在 ForkJoinPool 类中执行任务的线程

5、并行流

流可以处理某一种数据结构的所有元素,生成新的结构,筛选数据和使用 MapReduce 方法来实现算法

  • Stream接口:该接口定义了一个流的操作
  • Optional:这是一个容器对象,可能包含一个非空值
  • Collectors:该类实现了 reduction 操作
  • lambda表达式:大多数方法流可以接受 lambda 表达式作为参数

6、并发数据结构

分为阻塞和非阻塞两种

  • ConcurrentLinkedDeque:非阻塞型列表
  • ConcurrentLinkedQueue:非阻塞型队列
  • LinkedBlockingDeque:阻塞型的列表
  • LinkedBlockingQueue:阻塞型的队列
  • PriorityBlockingQueue:基于优先级对元素进行排序的阻塞型队列
  • ConcurrentSkipListMap:非阻塞型的 NavigableMap
  • ConcurrentHashMap:非阻塞型的 hash 表
  • AtomicBooleanAtomicIntegerAtomicLongAtomicReference:基本的 java 原子类