Java并发常用类

1、分类

Atomic包,locks包,线程池&并发集合。

2、并发集合

(1)ConcurrentHashMap

    建立在HashMap基础上,jdk1.7时是由多个Segement组成,每个Segment里面类似HashMap结构,默认是有16个Segement,此时最多可以允许16个线程并发操作,Segement指定后不可扩容;jdk1.8时抛弃了分段锁,结构上和HashMap一直,链表加红黑树。

    jdk1.7的结构:

jsk1.7的concurrentHashMap

    每一个Segment都是一个HashEntry<K,V>[] table。

    public class ConcurrentHashMap extends AbstractMap implements ConcurrentMap,Serializable{

        // 将整个hashmap分成几个小的map,每个segment都是一个锁;与hashtable相比,这么设计的目的是对于put, remove等操作,可以减少并发冲突,对不属于同一个片段的节点可以并发操作,大大提高了性能

        final Segment[] segments;

        // 本质上Segment类就是一个小的hashmap,里面table数组存储了各个节点的数据,继承了ReentrantLock, 可以作为互拆锁使用

        static final class Segment extends ReentrantLock implements Serializable{ 

         transient volatile HashEntry[] table;

         transient int count;

        }

        // 基本节点,存储Key, Value值

        static final class HashEntry{

            final int hash;

            final K key; 

           volatile V value; 

           volatile HashEntry next;

        }

    }

    jdk1.8的结构:

    取消了segements字段,直接采用 transient volatile HashEntry[] table 保存数据,采用table数组元素作为锁,从而实现了对每一行数据进行加锁,进一步减少并发冲突的概率。

    将table数组+单向链表的数据结构,变更为table数组+单向链表+红黑树的结构。单向链表的时间复杂度为O(n),红黑树的时间复杂度为O(logN)。

(2)CopyOnWriteArrayList

    CopyOnWriteArrayList是一个线程安全的ArrayList,读操作无锁,add操作时采用拷贝一个新数组来操作,读效率很高,但是有可能有脏读。

    原理:

    在CopyOnWriteArrayList中,读操作不同步,因为他们在内部数据的快照上工作,所以多个迭代器可以同时遍历而不会相互阻塞。

    所有的写操作都是同步的,他们在备份数组的副本上工作,写操作完成后,将原阵列替换为复制的阵列,并释放锁定。支持数据变得易变,所以替换数组是原子操作。

    写操作后创建的迭代器将能够看到修改的结构。

    写时复制集合返回的迭代器不会抛出ConcurrentModificationException,因为他们在数组的快照上工作,并且无论后续怎么修改,都会像迭代器创建时那样完全返回元素,这里就可能出现脏读现象。

    源码解析:

       /** The lock protecting all mutators ,执行写时复制操作,需要使用可重入锁加锁*/

        final transient ReentrantLock lock =newReentrantLock();

       /** The array, accessed only via getArray/setArray. 对象数组,用于存放元素 */

        private transient volatile Object[] array;

    添加操作:

    finalReentrantLock lock = this.lock; 

    lock.lock();

    try{ 

         Object[] elements = getArray();

         int len = elements.length;

        //拷贝原容器,长度为原容器长度加一

        Object[] newElements = Arrays.copyOf(elements, len +1);

        //在新副本上执行添加操作

        newElements[len] = e;

        //将原容器引用指向新副本

        setArray(newElements);

        return true; 

     }finally{

        //解锁

       lock.unlock();

    }

(3)CopyOnWriteArraySet

    基于CopyOnWriteArrayList实现,但是添加时需要遍历一下元素存在与否,所以效率会低一点;hashSet也是在添加的时候遍历,但是不是顺序遍历,hashSet是基于hashMap实现的,所以根据hashcode确定位置后,直接定位元素。

(4)BlockingQueue

    实现类有ArrayBlockingQueue基于数组先进先出,有界;LinkedBlockingQueue基于链表,默认无界,可指定容量;PriorityBlockingQueue 无界。

3、lock

(1)AQS

    提供基于Lock接口的并发基础类,主要使用CAS实现。目的是在并发状态下管理被阻塞的线程。提供了一套通用的机制来管理同步状态,阻塞/唤醒线程,管理等待队列等。提供了acquire()、acquireShared()、release()、releaseShared()、hasWaiters()、cas改状态等方法。核心是等待队列(CLH队列)。

(2)CLH队列

    双向链表,节点是对线程的包装,分独占和共享两种类型;用前一节点的某一属性表示后一节点的状态;自旋方式不断cas插入包含当前线程的节点到尾部。

(3)Condition

    一般配合lock使用,await(),signal(),signalAll()。

(4)ReentrantLock

    基于AQS,里面有一个state值,先CAS设置state,如果state!=0,但发现拿锁的是自己则state++,获取失败的加到CLH队列尾,内部自选继续获取锁。

4、Atomic

(1)AtomicInteger

AtomicInteger源码

    里面由一个volatile修饰的value属性,为了保证值在线程间可见,并发操作采用CAS,可实现原子递增。

    源码解析:

getAndIncrement方法
unsafe.getAndAddInt方法

       其中var表示要被更新的对象,var2是原始值在内存中的偏移地址,通过getIntVolatile方法拿到现在的值var5,现在的var5是一个期望值。compareAndSwapInt是一个native方法,compareAndSwapInt(var1, var2, var5, var5 + var4)是根据var1和var2拿到内存中的值,和期望值var5比较,如果与期望值相等,就将其更新为var5+var4,该方法一直在尝试,直到内存中的值和期望值一样时,才能进行修改,并返回修改前内存的值。

    同时还提供了一个compareAndSet方法,当且仅当期望值和内存中的值相等时,才能执行更新操作,可以保证多线程同时修改共享变量时,只有一个线程可以修改成功。

(2) AtomicStampedReference

    CAS可能发生ABA问题,即一个变量原来是A,先被修改成B后,又修改回了A,由于CAS操作知识比较当前值和预期值是否一样,在其他线程来看,该变量就好像没有发生过改变。

    这种问题可以为数据添加一个时间戳,每次成功修改数据时,不仅修改数据的值,同时要更新时间戳的值,CAS操作时,不仅要比较当前值和预期值,还需要比较当前时间戳和预期时间戳,两者都满足时才能修改成功。

    AtomicStampedReference就是这样做的,它不仅维护对象之,还维护一个时间戳,当AtomicStampedReference对应的值被修改时,不仅要更新数据本身,还要更新时间戳(版本号)。

5、线程池

Executor接口,只有一个execute方法;Executors封装了一些常用线程池的方法;ExecutorService接口,继承Executor,新增shutdown,submit,invokeAll方法;ThreadPoolExcutor实现了ExecutorService,可用于创建线程池;Future接口,含cancel,get,isDone方法。

常用线程池,可以通过Executor调用创建,newFixedThreadPool,固定线程数量;newSingleThreadExecutor,单个线程;newCachedThreadPool,可调节线程数量线程池,有核心数量和最大数量;newSingleThreadSceduledExecutor,可以执行定时任务的线程池。

6、同步容器

同步容器主要包含Vector,Stack,HashTable,Collections类中提供静态工厂方法创建的类(Collections.synchronizedXxxx等方法)。

Vector实现了List接口,Vector实际上就是一个数组,和ArrayList类似,但是Vector中的方法都是synchronized方法。

Stack也是一个同步容器,它的方法也用了synchronized进行了同步,它实际上是继承了Cector类。

HashTable实现了Map接口,它和HashMap类似,但是HashTable进行了同步处理。

同步容器的缺陷:同步容器的原理就是在方法上使用synchronized修饰,那么这些方法每次只允许一个线程调用。所以其他视图调用这个方法的线程只能等待,那么性能就比非同步容器差。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,843评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,538评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,187评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,264评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,289评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,231评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,116评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,945评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,367评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,581评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,754评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,458评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,068评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,692评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,842评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,797评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,654评论 2 354

推荐阅读更多精彩内容

  • layout: posttitle: 《Java并发编程的艺术》笔记categories: Javaexcerpt...
    xiaogmail阅读 5,817评论 1 19
  • 第2章 java并发机制的底层实现原理 Java中所使用的并发机制依赖于JVM的实现和CPU的指令。 2.1 vo...
    kennethan阅读 1,424评论 0 2
  • 九种基本数据类型的大小,以及他们的封装类。(1)九种基本数据类型和封装类 (2)自动装箱和自动拆箱 什么是自动装箱...
    关玮琳linSir阅读 1,883评论 0 47
  • Java8张图 11、字符串不变性 12、equals()方法、hashCode()方法的区别 13、...
    Miley_MOJIE阅读 3,701评论 0 11
  • 今天是感恩节,一切美好,皆因相遇。感谢生命中遇到的每一位朋友,祝大家身体健康,心想事成。永远相信更好的事情即将发生!
    狂飙阿凡阅读 667评论 0 0