Java并发编程之并发容器
解决并发情况下的容器线程安全问题的。给多线程环境准备一个线程安全的容器对象。
线程安全的容器对象: Vector, Hashtable。线程安全容器对象,都是使用 synchronized 方法实现的。
concurrent 包中的同步容器,大多数是使用系统底层技术实现的线程安全。类似 native。 Java8 中使用 CAS。
1、Map/Set
1.1 ConcurrentHashMap/ConcurrentHashSet
底层哈希实现的同步 Map(Set)。效率高,线程安全。使用系统底层技术实现线程安全。 量级较 synchronized 低。key 和 value 不能为 null。
1.2 ConcurrentSkipListMap/ConcurrentSkipListSet
底层跳表(SkipList)实现的同步 Map(Set)。有序,效率比 ConcurrentHashMap 稍低。
- import java.util.Map;
- import java.util.Random;
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.concurrent.CountDownLatch;
- public class Test_01_ConcurrentMap {
- public static void main(String[] args) {
- // final Map<String, String> map = new Hashtable<>();
- final Map<String, String> map = new ConcurrentHashMap<>();
- //ConcurrentSkipListMap跳表实现的,是排序的,最慢
- // final Map<String, String> map = new ConcurrentSkipListMap<>();
- final Random r = new Random();
- Thread[] array = new Thread[100];
- final CountDownLatch latch = new CountDownLatch(array.length);
- long begin = System.currentTimeMillis();
- for (int i = 0; i < array.length; i++) {
- array[i] = new Thread(new Runnable() {
- @Override
- public void run() {
- for (int j = 0; j < 100000; j++) {
- map.put("key" + r.nextInt(100000), "value" + r.nextInt(100000));
- }
- latch.countDown();
- }
- });
- }
- for (Thread t : array) {
- t.start();
- }
- try {
- latch.await();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- long end = System.currentTimeMillis();
- System.out.println("执行时间为 : " + (end - begin) + "毫秒!");
- }
- }
2、List
2.1 CopyOnWriteArrayList
写时复制集合。写入效率低,读取效率高。每次写入数据,都会创建一个新的底层数组。
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Random;
- import java.util.concurrent.CountDownLatch;
- public class Test_02_CopyOnWriteList {
- public static void main(String[] args) {
- final List<String> list = new ArrayList<>();
- // final List<String> list = new Vector<>();
- // final List<String> list = new CopyOnWriteArrayList<>();
- final Random r = new Random();
- Thread[] array = new Thread[100];
- final CountDownLatch latch = new CountDownLatch(array.length);
- long begin = System.currentTimeMillis();
- for (int i = 0; i < array.length; i++) {
- array[i] = new Thread(new Runnable() {
- @Override
- public void run() {
- for (int j = 0; j < 1000; j++) {
- list.add("value" + r.nextInt(100000));
- }
- latch.countDown();
- }
- });
- }
- for (Thread t : array) {
- t.start();
- }
- try {
- latch.await();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- long end = System.currentTimeMillis();
- System.out.println("执行时间为 : " + (end - begin) + "毫秒!");
- System.out.println("List.size() : " + list.size());
- }
- }
3、Queue
3.1 ConcurrentLinkedQueue
基础链表同步队列。
- /**
- * 并发容器 - ConcurrentLinkedQueue
- * 队列 - 链表实现的。
- */
- import java.util.Queue;
- import java.util.concurrent.ConcurrentLinkedQueue;
- public class Test_03_ConcurrentLinkedQueue {
- public static void main(String[] args) {
- Queue<String> queue = new ConcurrentLinkedQueue<>();
- for (int i = 0; i < 10; i++) {
- queue.offer("value" + i);
- }
- System.out.println(queue);
- System.out.println(queue.size());
- // peek() -> 查看queue中的首数据
- System.out.println(queue.peek());
- System.out.println(queue.size());
- // poll() -> 获取queue中的首数据
- System.out.println(queue.poll());
- System.out.println(queue.size());
- }
- }
3.2 LinkedBlockingQueue
阻塞队列,队列容量不足自动阻塞,队列容量为 0 自动阻塞。
- /**
- * 并发容器 - LinkedBlockingQueue
- * 阻塞容器。
- * put & take - 自动阻塞。
- * put自动阻塞, 队列容量满后,自动阻塞
- * take自动阻塞方法, 队列容量为0后,自动阻塞。
- */
- import java.util.Random;
- import java.util.concurrent.BlockingQueue;
- import java.util.concurrent.LinkedBlockingQueue;
- import java.util.concurrent.TimeUnit;
- public class Test_04_LinkedBlockingQueue {
- final BlockingQueue<String> queue = new LinkedBlockingQueue<>();
- final Random r = new Random();
- public static void main(String[] args) {
- final Test_04_LinkedBlockingQueue t = new Test_04_LinkedBlockingQueue();
- new Thread(new Runnable() {
- @Override
- public void run() {
- while (true) {
- try {
- t.queue.put("value" + t.r.nextInt(1000));
- TimeUnit.SECONDS.sleep(1);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }, "producer").start();
- for (int i = 0; i < 3; i++) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- while (true) {
- try {
- System.out.println(Thread.currentThread().getName() +
- " - " + t.queue.take());
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }, "consumer" + i).start();
- }
- }
- }
3.3 ArrayBlockingQueue
底层数组实现的有界队列。自动阻塞。根据调用 API(add/put/offer)不同,有不同特 性。
当容量不足的时候,有阻塞能力。
add 方法在容量不足的时候,抛出异常。put 方法在容量不足的时候,阻塞等待。
offer 方法:
单参数 offer 方法,不阻塞。容量不足的时候,返回 false。当前新增数据操作放弃。 三参数 offer 方法(offer(value,times,timeunit)),容量不足的时候,阻塞 times 时长(单
位为 timeunit),如果在阻塞时长内,有容量空闲,新增数据返回 true。如果阻塞时长范围 内,无容量空闲,放弃新增数据,返回 false。
- /**
- * 并发容器 - ArrayBlockingQueue
- * 有界容器。
- */
- import java.util.concurrent.ArrayBlockingQueue;
- import java.util.concurrent.BlockingQueue;
- import java.util.concurrent.TimeUnit;
- public class Test_05_ArrayBlockingQueue {
- final BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
- public static void main(String[] args) {
- final Test_05_ArrayBlockingQueue t = new Test_05_ArrayBlockingQueue();
- for (int i = 0; i < 5; i++) {
- // System.out.println("add method : " + t.queue.add("value"+i));
- /*try {
- t.queue.put("put"+i);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("put method : " + i);*/
- // System.out.println("offer method : " + t.queue.offer("value"+i));
- try {
- System.out.println("offer method : " +
- t.queue.offer("value" + i, 1, TimeUnit.SECONDS));
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- System.out.println(t.queue);
- }
- }
3.4 DelayQueue
延时队列。根据比较机制,实现自定义处理顺序的队列。常用于定时任务。
如:定时关机。
- /**
- * 并发容器 - DelayQueue
- * 无界容器。
- */
- import java.util.concurrent.BlockingQueue;
- import java.util.concurrent.DelayQueue;
- import java.util.concurrent.Delayed;
- import java.util.concurrent.TimeUnit;
- public class Test_06_DelayQueue {
- static BlockingQueue<MyTask_06> queue = new DelayQueue<>();
- public static void main(String[] args) throws InterruptedException {
- long value = System.currentTimeMillis();
- MyTask_06 task1 = new MyTask_06(value + 2000);
- MyTask_06 task2 = new MyTask_06(value + 1000);
- MyTask_06 task3 = new MyTask_06(value + 3000);
- MyTask_06 task4 = new MyTask_06(value + 2500);
- MyTask_06 task5 = new MyTask_06(value + 1500);
- queue.put(task1);
- queue.put(task2);
- queue.put(task3);
- queue.put(task4);
- queue.put(task5);
- System.out.println(queue);
- System.out.println(value);
- for (int i = 0; i < 5; i++) {
- System.out.println(queue.take());
- }
- }
- }
- class MyTask_06 implements Delayed {
- private long compareValue;
- public MyTask_06(long compareValue) {
- this.compareValue = compareValue;
- }
- /**
- * 比较大小。自动实现升序
- * 建议和getDelay方法配合完成。
- * 如果在DelayQueue是需要按时间完成的计划任务,必须配合getDelay方法完成。
- */
- @Override
- public int compareTo(Delayed o) {
- return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
- }
- /**
- * 获取计划时长的方法。
- * 根据参数TimeUnit来决定,如何返回结果值。
- */
- @Override
- public long getDelay(TimeUnit unit) {
- return unit.convert(compareValue - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
- }
- @Override
- public String toString() {
- return "Task compare value is : " + this.compareValue;
- }
- }
3.5 LinkedTransferQueue
转移队列,是一个容量为 0 的队列。使用 transfer 方法,实现数据的即时处理。没有消费者,就阻塞。
- /**
- * 并发容器 - LinkedTransferQueue
- * 转移队列
- * add - 队列会保存数据,不做阻塞等待。
- * transfer - 是TransferQueue的特有方法。必须有消费者(take()方法的调用者)。
- * 如果没有任意线程消费数据,transfer方法阻塞。一般用于处理即时消息。
- */
- import java.util.concurrent.LinkedTransferQueue;
- import java.util.concurrent.TimeUnit;
- import java.util.concurrent.TransferQueue;
- public class Test_07_TransferQueue {
- TransferQueue<String> queue = new LinkedTransferQueue<>();
- public static void main(String[] args) {
- final Test_07_TransferQueue t = new Test_07_TransferQueue();
- /*new Thread(new Runnable() {
- @Override
- public void run() {
- try {
- System.out.println(Thread.currentThread().getName() + " thread begin " );
- System.out.println(Thread.currentThread().getName() + " - " + t.queue.take());
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }, "output thread").start();
- try {
- TimeUnit.SECONDS.sleep(2);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- try {
- t.queue.transfer("test string");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }*/
- new Thread(new Runnable() {
- @Override
- public void run() {
- try {
- t.queue.transfer("test string");
- // t.queue.add("test string");
- System.out.println("add ok");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }).start();
- try {
- TimeUnit.SECONDS.sleep(2);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- new Thread(new Runnable() {
- @Override
- public void run() {
- try {
- System.out.println(Thread.currentThread().getName() + " thread begin ");
- System.out.println(Thread.currentThread().getName() + " - " + t.queue.take());
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }, "output thread").start();
- }
- }
3.6 SynchronusQueue
同步队列,是一个容量为 0 的队列。是一个特殊的 TransferQueue。 必须现有消费线程等待,才能使用的队列。
add 方法,无阻塞。若没有消费线程阻塞等待数据,则抛出异常。 put 方法,有阻塞。若没有消费线程阻塞等待数据,则阻塞。
- /**
- * 并发容器 - SynchronousQueue
- */
- import java.util.concurrent.BlockingQueue;
- import java.util.concurrent.SynchronousQueue;
- import java.util.concurrent.TimeUnit;
- public class Test_08_SynchronusQueue {
- BlockingQueue<String> queue = new SynchronousQueue<>();
- public static void main(String[] args) {
- final Test_08_SynchronusQueue t = new Test_08_SynchronusQueue();
- new Thread(new Runnable() {
- @Override
- public void run() {
- try {
- System.out.println(Thread.currentThread().getName() + " thread begin ");
- try {
- TimeUnit.SECONDS.sleep(2);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(Thread.currentThread().getName() + " - " + t.queue.take());
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }, "output thread").start();
- /*try {
- TimeUnit.SECONDS.sleep(3);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }*/
- // t.queue.add("test add");
- try {
- t.queue.put("test put");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(Thread.currentThread().getName() + " queue size : " + t.queue.size());
- }
- }
Java并发编程之并发容器的更多相关文章
- Java并发编程:同步容器
Java并发编程:同步容器 为了方便编写出线程安全的程序,Java里面提供了一些线程安全类和并发工具,比如:同步容器.并发容器.阻塞队列.Synchronizer(比如CountDownLatch). ...
- Java并发编程:并发容器ConcurrentHashMap
Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concu ...
- 【转】Java并发编程:同步容器
为了方便编写出线程安全的程序,Java里面提供了一些线程安全类和并发工具,比如:同步容器.并发容器.阻塞队列.Synchronizer(比如CountDownLatch).今天我们就来讨论下同步容器. ...
- 8、Java并发编程:同步容器
Java并发编程:同步容器 为了方便编写出线程安全的程序,Java里面提供了一些线程安全类和并发工具,比如:同步容器.并发容器.阻塞队列.Synchronizer(比如CountDownLatch). ...
- Java并发编程:并发容器之CopyOnWriteArrayList(转载)
Java并发编程:并发容器之CopyOnWriteArrayList(转载) 原文链接: http://ifeve.com/java-copy-on-write/ Copy-On-Write简称COW ...
- Java并发编程:并发容器之ConcurrentHashMap(转载)
Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concu ...
- Java并发编程:并发容器之ConcurrentHashMap
转载: Java并发编程:并发容器之ConcurrentHashMap JDK5中添加了新的concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为同步容器将所有对容器状态的 ...
- Java并发编程:并发容器之CopyOnWriteArrayList
转载: Java并发编程:并发容器之CopyOnWriteArrayList Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个 ...
- 【转】Java并发编程:并发容器之CopyOnWriteArrayList
Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改, ...
- 【转】Java并发编程:并发容器之ConcurrentHashMap
JDK5中添加了新的concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为同步容器将所有对容器状态的访问都串行化了,这样保证了线程的安全性,所以这种方法的代价就是严重降低了 ...
随机推荐
- 如何让SQLServer的 itemNum 字段 按照数字大小顺序排序
我的 itemNum 从1到20,可是超过了SQLServer的默认排序这样的1101112...19234567如何才能让排序成为这样1234567891011.. . 解决办法:因为 itemNu ...
- Ubuntu下安装Snap
介绍 Snap是一个全新的软件包架构,它与其它包管理器的区别在于snap安装的app互相之间是高度隔离的,减少了互相引用. 避免了很多冲突问题. 不过这也导致了其占用的磁盘比较多. 安装 apt in ...
- 搭建zookeeper+kafka集群
搭建zookeeper+kafka集群 一.环境及准备 集群环境: 软件版本: 部署前操作: 关闭防火墙,关闭selinux(生产环境按需关闭或打开) 同步服务器时间,选择公网ntpd服务器或 ...
- java类的生命周期
https://www.cnblogs.com/aspirant/p/7200523.html 验证的内容:文件格式,字节码,符号引用,元数据 准备:给静态变量分配内存设置初始值(0) 初始化才是真正 ...
- Oracle数据库中OVER()函数的了解
1.over函数介绍: 开窗函数,Oracle从8.1.6开始提供分析函数,分析函数用于计算基于组的某种聚合值,它和聚合函数的不同之处是:对于每个组返回多行,而聚合函数对于每个组只返回一行. ...
- [C#]位运算符
参考链接: http://www.runoob.com/csharp/csharp-operators.html 表: 简单来说,就是: &:全1为1,否则为0 |:有1为1,否则为0 ^:不 ...
- 06 Jquery 基础
前端学习之jquery: jQuery:一个库 Jquery的基础语法: $(selector).action() 基本选择器: <script> //基本选择器 //$("*& ...
- C#对象与XMl文件之间的相互转换(转)
本文是对C#中对象与XMl文件之间的相互转换进行了详细的介绍,需要的朋友可以过来参考下,希望对大家有所帮助 C#提供三种序列化方式,分别为:1.是使用BinaryFormatter进行串行化: 2.使 ...
- django原生sql查询如何返回字典格式
django原生sql查询,默认返回的是元祖.如果想返回字典格式,需要自行封装: http://www.360doc.com/content/17/0802/11/9200790_676042880. ...
- JS写一个简单日历
JS写一个日历,配合jQuery操作DOM <!DOCTYPE html> <html> <head> <meta charset="UTF-8&q ...