非阻塞线程安全列表——ConcurrentLinkedDeque应用举例

在java中,最常用的数据结构可能是列表。有数目不详的元素列表,你可以添加、阅读、或删除任何位置的元素。此外,并发列表允许不同的线程列表中添加或删除元素时不产生任何数据不一致。非阻塞列表提供如下操作,如果操作不能立即完成,列出抛出异常或者返回一个null值。Java 7中引入了ConcurrentLinkedDeque类,它实现了一个非阻塞并发列表,在本教程中,我们将学习使用这个类。

在这个例子中,我们将实现一个示例使用以下两个不同的任务:

一个将大量数据添加到一个列表中

一个大量地从同样的列表中删除数据

让我们为每个任务创建的线程:

package com.howtodoinjava.demo.multithreading.concurrentLinkedDequeExample;

import java.util.concurrent.ConcurrentLinkedDeque;

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 + ": Element " + i);
        }
    }
}

和:

package
com.howtodoinjava.demo.multithreading.concurrentLinkedDequeExample;

import
java.util.concurrent.ConcurrentLinkedDeque;

public
class
RemoveTask 
implements
Runnable {

    private
ConcurrentLinkedDeque<String> list;

    public
RemoveTask(ConcurrentLinkedDeque<String> list) {

        this.list = list;

    }

    @Override

    public
void
run() {

        for
(int
i = 0; i < 5000; i++) {

            list.pollFirst();

            list.pollLast();

        }

    }

}

现在,让我们创建100个线程将数据添加到列表和100个线程从列表删除数据。如果真的是线程安全的和非阻塞,它会几乎立即给你最终结果。此外,列表大小最终将是零。

package com.howtodoinjava.demo.multithreading.concurrentLinkedDequeExample;

import java.util.concurrent.ConcurrentLinkedDeque;

public class Main {
    public static void main(String[] args)
    {
        ConcurrentLinkedDeque<String> list = new ConcurrentLinkedDeque<>();
        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();
        }
        System.out.printf("Main: %d AddTask threads have been launched\n", threads.length);

        for (int i = 0; i < threads.length; i++) {
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.printf("Main: Size of the List: %d\n", list.size());

        for (int i = 0; i < threads.length; i++) {
            RemoveTask task = new RemoveTask(list);
            threads[i] = new Thread(task);
            threads[i].start();
        }
        System.out.printf("Main: %d RemoveTask threads have been launched\n", threads.length);

        for (int i = 0; i < threads.length; i++) {
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.printf("Main: Size of the List: %d\n", list.size());
    }
}

Output:

Main: 100 AddTask threads have been launched
Main: Size of the List: 1000000
Main: 100 RemoveTask threads have been launched
Main: Size of the List: 0

让我们看看它如何工作:

  1. 首先,你有100执行 AddTask将元素添加到任务列表。每一个这些任务插入10000个元素的列表使用 add()方法。这种方法增加了新元素列表的最后。当所有这些任务已经完成了,你写在控制台的数量列表的元素。这时,有1000000个元素的列表。
  2. 然后,你有100执行 RemoveTask任务来从列表中删除元素。每一个这些任务删除使用10000个元素的列表 pollFirst()pollLast()方法。pollFirst()方法返回和删除列表的第一个元素和pollLast()方法返回和删除最后一个元素的列表。如果列表为空,这些方法返回一个null值。当所有这些任务已经完成了,你写在控制台的数量列表的元素。这时,有零元素列表。
  3. 编写列表的元素的数量,你使用了 size()方法。你必须考虑,这种方法可以返回一个值,并不是真实的,特别是如果你使用它当线程列表中添加或删除数据。计数的方法遍历整个列表的元素和内容列表可以改变这个操作。只有在你使用它们时没有任何线程修改列表,你可以保证返回的结果是正确的。

请注意, ConcurrentLinkedDeque类提供了更多的方法来获取元素列表形式:

  • getFirst() getLast():这些方法返回分别从列表中第一个和最后一个元素。他们不会从列表中删除返回的元素。如果列表是空的,这些方法抛出一个 NoSuchElementExcpetion例外。
  • peek(), peekFirst(), peekLast():这些方法返回列表的第一个和最后一个元素。他们不会从列表中删除返回的元素。如果列表为空,这些方法返回一个null值。
  • remove(), removeFirst(), removeLast():这些方法返回列表的第一个和最后一个元素。他们从列表中移除返回的元素。如果列表是空的,这些方法抛出一个 NoSuchElementException例外。
  • 一个 ConcurrentLinkedDeque是一个合适的选择,许多线程共享访问公共集合。
  • 像大多数其他并发集合实现,这个类不允许null元素的使用。
  • 迭代器是弱一致的,返回元素反映在一些点或双端队列的状态,因为迭代器的创建。他们不把ConcurrentModificationException与其他操作,可以同时进行。

快乐学习!
!

原文链接:http://howtodoinjava.com/2015/02/23/non-blocking-thread-safe-list-concurrentlinkeddeque-example/

时间: 2024-10-10 09:03:49

非阻塞线程安全列表——ConcurrentLinkedDeque应用举例的相关文章

tornado 异步调用系统命令和非阻塞线程池

项目中异步调用 ping 和 nmap 实现对目标 ip 和所在网关的探测 Subprocess.STREAM 不用担心进程返回数据过大造成的死锁, Subprocess.PIPE 会有这个问题. import tornado.gen from tornado.process import Subprocess @tornado.gen.coroutine def run_command(command): """run command""" p

java多线程 --ConcurrentLinkedQueue 非阻塞 线程安全队列

ConcurrentLinkedQueue是一个基于链接节点的无界线程安全队列,它采用先进先出的规则对节点进行排序,当我们添加一个元素的时候,它会添加到队列的尾部:当我们获取一个元素时,它会返回队列头部的元素.它采用了"wait-free"算法(即CAS算法)来实现. 阻塞队列BlockingQueue: 支持阻塞的插入方法:意思是当队列满时,队列会阻塞插入元素的线程,直到队列不满. 支持阻塞的移除方法:意思是在队列为空时,获取元素的线程会等待队列变为非空. Java里的阻塞队列 Ar

(转)同步异步/阻塞非阻塞 和 5种linux网络通信模型

会阻塞的函数:connect, accept,send/recv/sendto/recvfrom等读写函数. 不会阻塞的函数:bind, listen,socket, closesocket. linux网络通信模型有: 阻塞IO模型(同步),非阻塞IO模型(拷贝同步),IO复用模型(多线程同步),信号驱动IO模型((拷贝同步),异步IO模型(异步). node.js对同步/异步,阻塞非阻塞的解释: 线程在执行中如果遇到磁盘读写或网络通信(统称为I/O 操作),通常要耗费较长的时间,这时 操作系

Java多线程之~~~线程安全容器的非阻塞容器

在并发编程中,会经常遇到使用容器.但是如果一个容器不是线程安全的,那么他在多线程的插入或者删除的过程 中就会出现各种问题,就是不同步的问题.所以JDK提供了线程安全的容器,他能保证容器在多线程的情况下安全的插 入和删除.当然,线程安全的容器分为两种,第一种为非阻塞似的,非阻塞的意思是当请求一个容器为空或者这个请求 不能执行的时候,就会报出异常,第二种阻塞的意思是,不能执行的命令不会报出异常,他会等待直到他能执行.下面 我们实现一个例子,这个例子就是多个线程去大量的插入容器数据,而另一个线程去大量

# 进程/线程/协程 # IO:同步/异步/阻塞/非阻塞 # greenlet gevent # 事件驱动与异步IO # Select\Poll\Epoll异步IO 以及selectors模块 # Python队列/RabbitMQ队列

1 # 进程/线程/协程 2 # IO:同步/异步/阻塞/非阻塞 3 # greenlet gevent 4 # 事件驱动与异步IO 5 # Select\Poll\Epoll异步IO 以及selectors模块 6 # Python队列/RabbitMQ队列 7 8 ############################################################################################## 9 1.什么是进程?进程和程序之间有什么

python第三十七天,GIL全局解释器锁*****,线程池与进程池 同步异步,阻塞与非阻塞,异步回调

GIL全局解释器锁 1.什么是GIL 官方解释:'''In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe

(一) 这就是所谓的Node.js------单线程,非阻塞,事件驱动

Node.js 第一天笔记(V1) 一:Node.js到底是从何而来 2008年的秋天,一个名叫做Ryan Dahl(罗伊?达尔)的年轻人在玩了几年服务器编程之后,越发感到服务器高并发性能的瓶颈是一个很难逾越的问题.无论是自己擅长的Ruby on Rails,还是传统的LAMP.以及C或者Lua.都各有各的缺陷.Ruby的虚拟机太烂,C虽然性能比较高,但是天生的语言本身缺憾致使开发Web的效率低下.Lua则是已有的同步I/O问题导致无法发挥性能优势. Ryan使用了这些语言开发Web服务器几年之

线程安全与线程不安全,阻塞与非阻塞

什么叫线程安全?这个首先要明确.线程安全的类 ,指的是类内共享的全局变量的访问必须保证是不受多线程形式影响的.如果由于多线程的访问(比如修改.遍历.查看)而使这些变量结构被破坏或者针对这些变量操作的原子性被破坏,则这个类就不是线程安全的. 阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态下,cpu不会给线程分配时间片,即线程暂停运行).函数只有在得到结果之后才会返回. 非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回. 参考

进程&amp;线程 同步异步&amp;阻塞非阻塞

2015-08-19 15:23:38 周三 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码 线程安全问题都是由全局变量及静态变量引起的 若每个线程中对全局变量.静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的:若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全 线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用 线程不安全就是不提供数