java并发系列——并发集合(一)

来源:互联网 发布:尽人事知天命下一句 编辑:程序博客网 时间:2024/05/17 04:22

一、介绍

在编程语言中,数据结构是一种能为计算机提供数据存储的元素,在java语言中,提供了集合框架,实现不同类型的数据结构的属性,类和接口等,可以应用于程序中。
在并发编程中,常用的大多数集合并不适用,因为它们没有控制数据
的并发访问,当多个并发线程访问同一个共享的数据结构时,会造成数据的不正确性。比如ArrayList,HashMap等。

(1)、当然java提供了可以在并发中使用的,不会出现问题且可保证数据一致的集合,可以分为如下两种:
1.阻塞集合
这种集合包括添加和删除数据的操作。如果操作不能立即进行,是因为集合已满或者为空,该程序将被阻塞,直到操作可以进行。
2.非阻塞集合
这种集合也包括添加和删除数据的操作。如果操作不能立即进行,这个操作将返回null值或抛出异常,但该线程将不会阻塞。

(2)、在并发编程中常用的一些集合列表:

  • 非阻塞列表,使用ConcurrentLinkedDeque类。
  • 阻塞列表,使用LinkedBlockingDeque类。
  • 用在生产者与消费者数据的阻塞列表,使用LinkedTransferQueue类。
  • 使用优先级排序元素的阻塞列表,使用PriorityBlockingQueue类。
  • 存储延迟元素的阻塞列表,使用DelayQueue类。
  • 非阻塞可导航的map,使用ConcurrentSkipListMap类。
  • 随机数,使用ThreadLocalRandom类。
  • 原子变量,使用AtomicLong和AtomicIntegerArray类。

二、非阻塞线程安全列表

(1)、列表(List):是最基本的线性集合元素,一个列表有不确定的元素数量,并且你可以添加、读取和删除任意位置上的元素。并发列表允许不同的线程在同一时刻对列表的元素进行添加或删除,而不会产生任何数据不一致(问题)。
(2)、ConcurrentLinekedQueue的使用,它是非阻塞的,若操作不能立即完成,它将根据此操作返回null或抛出异常。
下面来实现一个例子:
1.往列表中大量添加数据;
2.在同个列表中,进行数据的大量删除
程序实现:
1.增加任务类

public class AddTask implements Runnable {    private ConcurrentLinkedDeque<String> list;    public AddTask(ConcurrentLinkedDeque<String> list){        this.list=list;    }    @Override    public void run() {        String name=Thread.currentThread().getName();        for(int i=0;i<10000;i++){            list.add(name+":"+i);        }    }}

2.删除任务类

public class PollTask implements Runnable {    private ConcurrentLinkedDeque<String> list;    public PollTask(ConcurrentLinkedDeque<String> list){        this.list=list;    }    @Override    public void run() {        for(int i=0;i<5000;i++){            list.pollFirst();            list.pollLast();        }    }}

3.测试类

@Test    public void tesConcurrentLinkedDeque(){        ConcurrentLinkedDeque<String> list=new ConcurrentLinkedDeque<String>();        Thread threads[]=new Thread[100];        for(int i=0;i<threads.length;i++){            AddTask task=new AddTask(list);            threads[i]=new Thread(task);            threads[i].start();        }        //使用join方法等待这些线程的完成        for(int i=0;i<threads.length;i++){            try {                threads[i].join();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        System.out.printf("Size of the List: %d\n",list.size());        for (int i=0; i<threads.length; i++){            PollTask task=new PollTask(list);            threads[i]=new Thread(task);            threads[i].start();            }        System.out.printf("Main: %d PollTask threads have been launched\n",threads.length);        //使用join方法等待这些线程的完成        for(int i=0;i<threads.length;i++){            try {                threads[i].join();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        System.out.printf("Size of the List: %d\n",list.size());    }

4、运行结果
这里写图片描述

(3)、 实现说明:
1.创建100个增加任务的线程(AddTask),将并发的list初始化到线程中
2.每个线程会在list的尾部插入新的元素,插入10000个元素,则list的大小为
3.用join方法等待线程创建完成,才开始执行下面操作
4.创建100个删除任务的线程(PollTask)
5.每个PollTask会执行pollFirst()删除头部元素,执行pollLast()删除尾部元素,若列表为空,则返回null
6.利用list的size()方法,打印列表元素中的量。

0 0
原创粉丝点击