Java 并发编程(九)并发集合框架

集合框架简介

编程中,我们经常需要集中存放多个数据。数组是我们的一个很好的选择,前提是我们事先明确我们将要保存对象的数量。数组在初始化时如果指定了长度,那这个数组长度就是不可变的了,如果我们需要保存一个可以动态增长的数据(编译时无法确定具体的对象数量),所以Java提供了集合框架来实现这个功能。

集合类主要负责保存数据,因此集合类也被称为容器类。Java中集合类都位于java.util包下,后来为了处理多线程并发安全问题,Java5在java.util.concurrent包下提供了支持多线程并发的集合类。

Java容器类的用途是”保存对象”,并将其划分为两个不同的概念:

  1. Collection
    一组”对立”的元素,通常这些元素都服从某种规则
      1.1) List必须保持元素特定的顺序
      1.2) Set不能有重复元素
      1.3) Queue保持一个队列(先进先出)的顺序
  2. Map
    一组成对的”键值对”对象

Collection和Map的区别在于容器中每个位置保存的元素个数:

  • Collection 每个位置只能保存一个元素(对象)
  • Map保存的是”键值对”,我们可以通过”键”找到该键对应的”值”

Java集合框架Collection图示:

Java 并发编程(九)并发集合框架_第1张图片

Map集合框架图示:
Java 并发编程(九)并发集合框架_第2张图片

Java并发集合框架

我们着重说明一下Java并发的集合框架,就是java.util.concurrent包下的集合类

非阻塞队列

非阻塞队列就是在队列中没有数据时,对此队列的操作将出现异常或者返回null,无需等待/阻塞的特色。

在JDK的并发包中,常见的非阻塞队列有以下几个:
- ConcurrentHashMap
- ConcurrentSkipListMap
- ConcurrentSkipListSet
- ConcurrentLinkedQueue
- ConcurrentLinkedDeque
- CopyOnWriteArrayList
- CopyOnWriteArraySet

ConcurrentHashMap类

这个类是支持并发操作的Map对象,与之对应的不支持并发操作的Map对象是HashMap,Hashtable对象也是Map的一个子类,也是支持并发操作,但是其不支持Iterator并发的删除操作,如果程序中要对map集合做并发以及Iterator并发编辑/删除操作,推荐使用ConcurrentHashMap集合类。

HashMap集合不支持并发示例:

package com.collections.hashmapdemo;

import java.util.HashMap;

public class HashMapDemo {
    public static HashMap hashMap = new HashMap();

    public static void main(String[] args) {
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 50000; i++) {
                    hashMap.put("ThreadA" + (i + 1), "ThreadA" + i + 1);
                    System.out.println("ThreadA" + (i + 1));
                }
            }
        });

        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 50000; i++) {
                    hashMap.put("ThreadB" + (i + 1), "ThreadB" + i + 1);
                    System.out.println("ThreadB" + (i + 1));
                }
            }
        });

        threadA.start();
        threadB.start();
    }
}

执行结果
有时候程序可以正常执行完,有时候则程序会造成假死的状态,如下图:

Java 并发编程(九)并发集合框架_第3张图片

所以说HashMap不支持多线程并发的操作。

Hashtable集合支持并发
示例:
只需要把HashMap示例中public static HashMap hashMap = new HashMap();修改成public static Hashtable hashtable = new Hashtable();即可。
我们就说说Hashtable不支持Iterator的编辑/删除操作,示例如下

package com.collections.hashmapdemo;

import java.util.Hashtable;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;

public class HashtableNotModifyDemo {
    public static Hashtable hashtable = new Hashtable();
    static {
        for (int i = 0; i < 5; i++) {
            hashtable.put("String" + (i + 1), i + 1);
        }
    }

    public static void main(String[] args) {
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Iterator iterator = hashtable.keySet().iterator();
                    while (iterator.hasNext()) {
                        System.out.println(iterator.next());
                        TimeUnit.SECONDS.sleep(2);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                hashtable.put("z", "zValue");
            }
        });

        threadA.start();
        threadB.start();
    }
}

执行结果

String5
java.util.ConcurrentModificationException
at java.util.Hashtable Enumerator.next(Hashtable.java:1167)atcom.collections.hashmapdemo.HashtableNotModifyDemo 1.run(HashtableNotModifyDemo.java:22)
at java.lang.Thread.run(Thread.java:745)

说明多线程调用该类的iterator()方法返回Iterator对象后,在调用put方法会报ConcurrentModificationException异常,也就是不支持Iterator并发的编辑/删除操作。如果想实现此功能推荐使用并发集合框架提供的ConcurrentHashMap类。

ConcurrentHashMap集合支持并发示例:

需要把HashMap示例中public static HashMap hashMap = new HashMap();修改成public
static ConcurrentHashMap concurretHashMap = new ConcurrentHashMap();即可。

ConcurrentHashMap集合支持Iterator并发操作示例:

把类HashtableNotModifyDemo中的public static Hashtable hashtable = new Hashtable();修改为public static ConcurrentHashMap concurretHashMap = new ConcurrentHashMap();测试即可。

ConcurrentSkipListMap类

这个并发集合类支持排序功能。一般此集合中存放的对象要实现Comparable接口,方便此集合类排序,如果不实现此接口,则会按照默认排序。

ConcurrentSkipListSet类

这个并发集合类不仅支持排序功能,还不允许重复的元素。一般此集合中存放的对象要实现Comparable接口,并且重写equals和hashCode方法。

ConcurrentLinkedQueue类

这个并发集合类提供了并发环境的队列操作。

  • poll()当没有获取到数据时返回null,如果有数据则一处表头并将表头数据返回。
  • element()当没有获取到数据时抛NoSuchElementException异常,如果有数据则返回表头数据。
  • peek()当没有获取导数据是返回null,获取到数据时则不移除表头,并将表头数据返回。

ConcurrentLinkedDeque类

ConcurrentLinkedQueue支持对队列头操作,而ConcurrentLinkedDeque也支持队列头和列尾双向操作。

CopyOnWriteArrayList类

ArrayList是线程不安全的,如果想在并发中实现线程安全,则可以使用CopyOnWriteArrayList类,使用方法和ArrayList无异。

CopyOnWriteArraySet类

ArraySet是线程不安全的,如果想在并发中实现线程安全,则可以使用CopyOnWriteArraySet类,使用方法和ArraySet无异。

阻塞队列

to be continue……

你可能感兴趣的:(Java,并发编程)