概述

并发处理本身就是编程开发重点之一,同时内容也很繁杂,从底层指令处理到上层应用开发都要涉及,也是最容易出问题的地方。这块知识也是评价一个开发人员水平的重要指标,本人自认为现在也只是学其皮毛,因此本文重点介绍java的并发相关体系,具体的点懂得就多讲,不懂得就给出参考文章。先来看图:

本文重点介绍jdk中concurrent的内容,并发相关基础不在介绍,如果想系统的学习,建议直接看并发大作《java并发编程实践》吧(之前看过,可惜很多地方没懂),博客终究只是快餐,增强学习拓展知识很好,但打基础还是要看书实战的。

java内存模型

直接盗图一张(图寝删),详细讲解参考博客

java内存模型的作用可以理解为抽象了线程私有内存与主存(共享内存或堆)的关系,也就是原子性、可见性、顺序性的原则,而后介绍的内容都是为了保证这些原则的实现手段。

实现多线程的方法

这一块其实不必多说,大家都很熟悉,这里简单对比下优缺点:

  • 继承Thread:由于java不支持多继承,所以用起来有很强的局限性,使用场景不多。
  • 实现Runnable接口:常用的方式,有点对比Thread,并且更方便实现资源共享(两者异同,重点在评论)
  • 实现Callable接口: 结合Future使用,可以获取线程执行结果
  • Executor:concurrent中提供的一个上层并发处理框架,底层也是基于上边三种实现,基于此实现了线程池、任务调度等类,为一些典型场景提供了便捷的实现手段。

实现同步的方法

这一块也是常用的,也仅对比介绍一下:

  • volatile:volatile保证了原子操作在线程间的可见性(注意仅能保证可见性),并且修饰对象的操作不会指令重排。对于一个原子操作可以保证其之间一致,但是原子操作真的很少,比如i++都不行。更多介绍
  • Atomic:原子类,,基于CAS原理实现,提供了基本类型和引用对应的类,能保证其基本操作的可见性,底层基于volatile和Unsafe类(一个线程安全相关类,可以调用底层native方法)。如果线程间的同步仅限于某个值的改变,则可考虑用该类(实际上多数时候即使适合用也能找到对应的上层封装类,而不必自己实现)
  • synchronized:最为常用的同步方法之一,可以分为同步方法和同步代码块两类,使用简单,唯一一定要搞清的是synchronized锁的对象是谁。(拓展:synchronized底层实现
  • wait/notify:同步几大原语之二(记得还有join吧),java的Object中已实现的native方法,常用来同步线程执行顺序或进度,然而多数场景concurrent也提供了对应工具类,所以一般使用时也应该优先使用对应的工具类
  • Lock:锁,主要有ReentrantLock和ReadWriteLock,该方式较synchronized的优势就是使用比较灵活,同步不再局限于代码块或者方法,可以在任何需要的地方加锁解锁。就性能方面,除非你用的是1.4之前的jdk,否则两者差异不大
  • ThreadLocal:线程本地变量,其内部是一个map,key为线程对象本身,value为对应变量的一个拷贝,每个线程使用该变量时实际使用的是其副本,以此解决多线程共享变量的竞争,需要注意的是改类型并不是解决同步问题的,而是解决资源共享问题的,每个线程使用各自的副本,相互之间不影响,但是该变量的值变化相互之间也是隔离的ThreadLocal深入剖析

concurrent包

JDK 1.5增加了java.util.concurrent包,其内部提供了大量并发相关类,大大简化了设计并发的程序开发。该包大致可分为四大块:Atomic、Lock、Executor、以及线程安全的集合类,由于集合类已经在该系列第一篇介绍过,因此这里重点介绍前三块,此外还有一些工具类,这里仅介绍几个常见的。

Atomic

前边已经介绍过,Atomic为修饰的对象提供了原子更新,保证了其更新在线程间的可见性,Atomic包内的原子类实现主要基于CAS原理,利用了Unsafe包提供的CAS方法,其中可以分为以下几类:

  • 原子更新基本类型类,提供了AtomicBoolean、AtomicInteger和AtomicLong,对于其他基本类型,可以参照其实现自行通过Unsafe的方法实现(实质上都是转成int处理)
  • 原子更新数组类:也提供了三种类型:AtomicIntegerArray、AtomicLongArray和AtomicReferenceArray
  • 原子更新引用类型:对于非基本类型提供的类,AtomicReference、AtomicReferenceFieldUpdater、AtomicMarkableReference
  • 原子更新字段类:这几个类主要用于更新类中的某个字段:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicStampedReference
    这些类使用方法类似,都是通过以下方法实现原子更新:
  • getAndSet(v):设置新值,返回旧值
  • compareAndSet(expectedValue, newValue):如果当前值(current value)等于期待的值(expectedValue), 则原子地更新指定值为新值(newValue), 如果更新成功,返回true, 否则返回false, 换句话可以这样说: 将原子变量设置为新的值, 但是如果从我上次看到的这个变量之后到现在被其他线程修改了(和我期望看到的值不符), 那么更新失败
    详细的使用可以参考Java中的Atomic包使用指南

Lock

Lock提供了一种更为灵活的同步方式,Lock下主要有以下类:

  • ReentrantLock:重入锁,其底层通过一个Sync的静态类实现加锁解锁。Sync继承自AbstractQueuedSynchronizer,该抽象类内部实现了一个链表,保存了请求获取锁的状态,同时其内部有一个状态值,用来表示锁是否被线程获取,其修改通过Unsafe包提供的CAS方法,以此可以保证其可见性。同时尤其内部实现也可以知道,之所以叫重入锁,是因为其提供了非阻塞的使用方式,如果使用tryLock方法,当lock时在发现锁已lock的情况下,会立即返回结果,而不会阻塞。使用示例
  • ReentrantReadWriteLock:可重入读写锁。实现原理和ReentrantLock一样,再次基础上增加了读写锁的操作。使用示例
  • Condition:实现类是AbstractQueuedSynchronizer中的一个内部类,其功能是实现线程间的协调通信,使得某个,或者某些线程一起等待某个条件(Condition),只有当该条件具备( signal 或者 signalAll方法被带调用)时 ,这些等待线程才会被唤醒,从而重新争夺锁。使用示例
  • LockSupport:可以看做对Unsafe包中并发原语的封装,为上层的锁实现提供原语操作。一般情况下上层开发很少用到。

Executor

Executor框架是concurrent中最常用的内容之一,其提供了一套能够便捷管理线程和任务的类,使我们能够很方便创建、调度一批具有同类操作的线程。其主要有以下几个类(接口):

  • Callable、Future:前边已经介绍过了,提供了一种可以获取返回值的线程实现方法,一般与
    ExecutorService配合使用。Callable使用
  • Executor:线程工具类,主要用于线程池、ThreadFactory、Callable实例。Executors详解
  • ThreadFactory:接口类,提供了创建线程个工厂类,多是时候配合线程池,作为参数传入为线程池提供创建线程的方法。
  • ExecutorService:接口类,是线程池实现类ThreadPoolExecutor的基类。
  • ExecutorCompletionService:与ExecutorService功能一样,不过其提供了poll()和take()两个方法用于获取线程执行结果,前者是非阻塞的,后者是阻塞的。
    使用示例

other

此外concurrent包还提供了一些其他类,这里仅列出功能,具体的使用可自行查询,这里给出一个比较完善的总结java.util.concurrent 用户指南

  • ForkJoinPool:和ExecutorService类似,不过其提供了fork和join的功能,能够将池内指定级别的任务进行分解或合并。这种处理方式与目前很多流处理框架类似,不过该实现使用的不多。
  • CountDownLatch:CountDownLatch 是一个线程协调器,它允许一个或多个线程等待一系列指定操作的完成。
    CountDownLatch 以一个给定的数量初始化。countDown() 每被调用一次,这一数量就减一。通过调用await() 方法之一,线程可以阻塞等待这一数量到达零。
  • CyclicBarrier:CyclicBarrier类也是一种同步机制,它可以在指定位置设定barrier,只有所有线程都执行到该位置是,才会继续向下执行。
  • Exchanger:该类提供了线程间交换数据的方法,可以视作一个管道。实现原理
  • Semaphore:信号量,学过操作系统的都知道,实现生产者—消费者的常用手段之一,信号量最大的用处是可以控制资源的访问数量,比起阻塞队列更加灵活。使用示例

其他

正如最开始所说的,并发相关的知识绝不是看一些知识点就可以掌握的,如果想要真正掌握,必须系统的学习。这里只是列出一些java相关的知识点,仅供参考。
最后再附两篇博文,有兴趣的可以看下:

图学java基础篇之并发的更多相关文章

  1. 图学java基础篇之IO

    java io体系 如图可以看出,java的io按照包来划分的话可以分为三大块:io.nio.aio,但是从使用角度来看,这三块其实揉杂在一起的,下边我们先来概述下这三块: io:主要包含字符流和字节 ...

  2. 图学java基础篇之集合

    (本文部分图片引用自其他博客,最后有链接,侵删.由于笔记使用markdown记录,格式可能不是太好看,见谅) 集合结构 红字为java.util包下的,绿字为concurrent包下扩展的与并发相关的 ...

  3. 图学java基础篇之集合工具

    两个工具类 java.utils下又两个集合相关_(准确来说其中一个是数组的)_的工具类:Arrays和Collections,其中提供了很多针对集合的操作,其中涵盖了一下几个方面: 拷贝.填充.反转 ...

  4. 金三银四跳槽季,BAT美团滴滴java面试大纲(带答案版)之一:Java基础篇

    Java基础篇: 题记:本系列文章,会尽量模拟面试现场对话情景, 用口语而非书面语 ,采用问答形式来展现.另外每一个问题都附上“延伸”,这部分内容是帮助小伙伴们更深的理解一些底层细节的补充,在面试中可 ...

  5. 小白—职场之Java基础篇

    java基础篇 java基础 目录 1.java是一种什么语言,jdk,jre,jvm三者的区别 2.java 1.5之后的三大版本 3.java跨平台及其原理 4.java 语言的特点 5.什么是字 ...

  6. Java基础篇(JVM)——类加载机制

    这是Java基础篇(JVM)的第二篇文章,紧接着上一篇字节码详解,这篇我们来详解Java的类加载机制,也就是如何把字节码代表的类信息加载进入内存中. 我们知道,不管是根据类新建对象,还是直接使用类变量 ...

  7. java基础篇---I/O技术

    java基础篇---I/O技术   对于任何程序设计语言而言,输入输出(I/O)系统都是比较复杂的而且还是比较核心的.在java.io.包中提供了相关的API. java中流的概念划分 流的方向: 输 ...

  8. java基础篇---HTTP协议

    java基础篇---HTTP协议   HTTP协议一直是自己的薄弱点,也没抽太多时间去看这方面的内容,今天兴致来了就在网上搜了下关于http协议,发现有园友写了一篇非常好的博文,博文地址:(http: ...

  9. java基础篇---I/O技术(三)

    接上一篇java基础篇---I/O技术(二) Java对象的序列化和反序列化 什么叫对象的序列化和反序列化 要想完成对象的输入或输出,还必须依靠对象输出流(ObjectOutputStream)和对象 ...

随机推荐

  1. IIS错误HTTP 错误 500.21 - Internal Server Error

    原因:在安装Framework v4.0之后,再启用IIS,导致Framework没有完全安装 解决:以管理员身份运行cmd->输入“%windir%\Microsoft.NET\Framewo ...

  2. 为什么要使用Vuex?

    为什么要使用Vuex? 1. 假如不使用 1.1 父子组件依赖同一个state 1.2 兄弟组件依赖同一个state 2. 用了Vuex之后 3. 方便记忆和理解

  3. Jackson使用手册

    引用jar:jackson-core,jackson-databind,jackson-annotations http://central.maven.org/maven2/com/fasterxm ...

  4. Servlet和JavaBean

    1.Servlet简介: Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间 ...

  5. CAD Import .NET支持AutoCAD DWG 2013

    CADSoftTools发布了CAD Import .NET 9一个新版本.NET开发库,可以提供给开发人员导入AutoCAD DWG.DXF.HPGL.PLT.CGM等格式的功能. 在新版本中,CA ...

  6. Eucalyptus-instance启动后查看运行状态

    1.前言 在eucalyptus中通过虚拟机模板,创建并启动一个虚拟机,这个时候虚拟机启动正常,但是外部一直无法访问也ping不通,正对这种情况我们如何检查排除问题呢? 两种检查问题的方法: 1).在 ...

  7. 一、基于Qt的图像矩形区域改色

    Qt环境下图像的打开和涂色 一.设计目标 能够在 Qt QtCreator 环境下打开常用图像格式文件,诸如 bmp.jpg.png 图像等,然后将他们转化为 Qt 中的 QImage 类,并进行矩形 ...

  8. matplotlib学习之(四)设置线条颜色、形状

    本文是学习<matplotlib for python developers>的一点笔记plot画图时可以设定线条参数.包括:颜色.线型.标记风格.1)控制颜色颜色之间的对应关系为b--- ...

  9. java poi读取excel公式,返回计算值(转)

    http://blog.csdn.net/CYZERO/article/details/6573015 经测试,确实可以 1 package hrds.zpf.poi;  2  3  import o ...

  10. 2017.12.25 Java中面向对象思想的深刻理解

    今日内容介绍 1.面向对象思想 2.类与对象的关系 3.局部变量和成员变量的关系 4.封装思想 5.private,this关键字 6.随机点名器 01面向对象和面向过程的思想 * A: 面向过程与面 ...