高并发编程基础(java.util.concurrent包常见类基础)
JDK5中添加了新的java.util.concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能。因为同步容器将所有对容器状态的访问都串行化了,这样保证了线程的安全性,所以这种方法的代价就是严重降低了并发性,当多个线程竞争容器时,吞吐量严重降低。因此JDK5开始针对多线程并发访问设计,提供了并发性能较好的并发容器,引入了java.util.concurrent包。与Vector和Hashtable、Collections.synchronizedXxx()同步容器等相比,util.concurrent中引入的并发容器主要解决了两个问题:
1)根据具体场景进行设计,尽量避免synchronized,提供并发性。
2)定义了一些并发安全的复合操作,并且保证并发环境下的迭代操作不会出错。
这里先粗略的介绍下 concurrrent 包下面常见并发容器的简单应用,后续再针对性的去深入研究。
并发容器:
public class T07_DelayQueue {
// 执行定时任务
static BlockingQueue<MyTask> tasks = new DelayQueue<>();
static Random r = new Random(); static class MyTask implements Delayed { long runningTime; MyTask(Long rt) { this.runningTime = rt;
}
@Override
public int compareTo(Delayed o) {
if (this.getDelay(TimeUnit.MILLISECONDS) < o.getDelay(TimeUnit.MILLISECONDS))
return -1;
if (this.getDelay(TimeUnit.MILLISECONDS) > o.getDelay(TimeUnit.MILLISECONDS))
return 1;
else
return 0;
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(runningTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
} @Override
public String toString() {
return "" + runningTime ;
}
}
public static void main(String[] args) throws InterruptedException {
long now = System.currentTimeMillis(); MyTask t1 =new MyTask(now +1000);
MyTask t2 =new MyTask(now +2000);
MyTask t3 =new MyTask(now +1500);
MyTask t4 =new MyTask(now +2500);
MyTask t5 =new MyTask(now +500); tasks.put(t1);
tasks.put(t2);
tasks.put(t3);
tasks.put(t4);
tasks.put(t5); System.out.println(tasks); for(int i=0;i<5;i++) {
System.out.println(tasks.take());
} }
}
ArrayBlockingQueue.class,阻塞队列,数组实现。有界阻塞队列
public class T06_ArrayBlockingQueue {
// 阻塞队列
static BlockingQueue<String> strs = new ArrayBlockingQueue<>(10);
static Random r =new Random();
public static void main(String[] args) throws InterruptedException {
for(int i=0;i<10;i++) {
strs.put("a"+i);
}
// strs.add("aaa");//Exception in thread "main" java.lang.IllegalStateException: Queue full
// strs.put("aaa"); // 满了会等待 阻塞
// strs.offer("aaa");//不会报异常 有返回值 true or false
// strs.offer("aaa",1,TimeUnit.SECONDS); // 按照时间段阻塞
}
}
LinkedBlockingDeque.class,阻塞双端队列,链表实现
LinkedBlockingQueue.class,阻塞队列,链表实现,无界,以下是该类对与生产者消费者模型的简单实现:
public class T05_LinkedBlockingQueue {
// 阻塞队列
static BlockingQueue<String> strs = new LinkedBlockingQueue<>(); static Random r =new Random();
//生产者消费者
public static void main(String[] args) {
new Thread(()->{
for(int i=0;i<100;i++) {
try {
strs.put("a"+i);//如果满了就会等待阻塞
System.err.println("a"+i);
TimeUnit.MILLISECONDS.sleep(r.nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"p1").start(); for(int i=0;i<5;i++) {
new Thread(()->{
while(true) {
try {
//take 如果空了 就会阻塞
System.out.println(Thread.currentThread().getName()+" take - "+ strs.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"c" +i).start();
}
}
}
SynchronousQueue.class,同步队列,但是队列长度为0,生产者放入队列的操作会被阻塞,直到消费者过来取,所以这个队列根本不需要空间存放元素;有点像一个独木桥,一次只能一人通过,还不能在桥上停留
public class T09_SynchronousQueue {
// 特殊的 transferQueue ,队列为空的
//任何添加东西都要直接丢给消费者的,不会往队列里加的
public static void main(String[] args) throws InterruptedException { BlockingQueue<String> strs = new SynchronousQueue<>(); new Thread(()->{
try {
System.out.println(strs.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
strs.put("aaa");//阻塞,等待消费者消费
// strs.add("aaa"); // 报错
System.out.println(strs.size());
}
}
ConcurrentLinkedQueue.class,非阻塞队列,链表实现
public class T04_ConcurrentQueue { public static void main(String[] args) {
Queue<String> strs = new ConcurrentLinkedQueue<>();
Queue<String> strs2 = new ConcurrentLinkedDeque<>();//双端队列 for(int i=0;i<10;i++) {
// 根据返回值来判断是否添加成功
strs.offer("a"+i);
} System.out.println(strs);//[a0, a1, a2, a3, a4, a5, a6, a7, a8, a9]
System.out.println(strs.size());// 10
System.out.println(strs.poll());// a0
System.out.println(strs.size());// 9
System.out.println(strs.peek());// a1
System.out.println(strs.size());// 9
}
}
LinkedTransferQueue.class,转移队列的链表实现,它比SynchronousQueue更快,transfer 方法有客户端准备消费,直接把消息直接传递给消费者,不放到队列里,没有消费者线程的话该线程会阻塞。但是可以调用 add put 王队列里丢,队列还是有容量的。
public class T08_TransferQueue { public static void main(String[] args) throws InterruptedException { LinkedTransferQueue<String> strs = new LinkedTransferQueue<>(); new Thread(()->{
try {
System.out.println(strs.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
strs.transfer("aaa");
// new Thread(()->{
// try {
// System.out.println(strs.take());
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }).start();
}
}
ConcurrentHashMap.class,并发HashMap,ConcurrentHashMap在并发中效率比 HashTable高,因为 HashTable 在往里添加东西的时候药锁定整个对象,而 ConcurrentHashMap 分成了16段,插入的时候只锁定了其中的一段,其实就是把锁细粒度化了,因此在多线程情况下回比 hashTable高 ,同样也比 Collections.synchronizedMap(map1) 高。
ConcurrentSkipListMap.class,跳表数据结构,它也是NavigableMap的实现类(要求元素之间可以比较),只有你确实需要快速的遍历操作,并且可以承受额外的插入开销的时候,在高并发中要求排序才去使用它。
public class T01_ConcurrentMap {
public static void main(String[] args) {
Map<String,String> map =new ConcurrentHashMap<>();//并发性比较高
// Map<String,String> map =new ConcurrentSkipListMap<>();//并发性高而且要求排序
// Map<String,String> map =new Hashtable<>();//并发性不是跟高
// Map<String,String> map1 =new HashMap<>();
// Map<String, String> map = Collections.synchronizedMap(map1);//并发性不是很高 Random r =new Random();
Thread[] ths =new Thread[100];
CountDownLatch latch =new CountDownLatch(ths.length);
long start = System.currentTimeMillis(); for(int i=0;i<ths.length;i++) {
ths[i]=new Thread(()->{
for(int j=0;j<10000;j++) {
map.put("a"+r.nextInt(10000), "a"+r.nextInt(10000));
}
latch.countDown();
});
}
Arrays.asList(ths).forEach(o->o.start());
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
} long end = System.currentTimeMillis();
System.out.println(end-start);
}
}
CopyOnWriteArraySet.class,和上面类似,list变成set而已
public class T01_CopyOnWriteList { public static void main(String[] args) {
List<String> lists =
// new Vector<String>();//并发效率相对高
// new ArrayList<String>();//这个并发会有问题
new CopyOnWriteArrayList<String>();//效率比较低,读取非常快,读的时候不加锁
Random r =new Random();
Thread[] ths =new Thread[100]; for(int i=0;i<ths.length;i++) {
ths[i]=new Thread(()->{
for(int j=0;j<1000;j++) {
lists.add("a"+r.nextInt(10000) );
}
});
}
long start = System.currentTimeMillis(); Arrays.asList(ths).forEach(o->o.start());
Arrays.asList(ths).forEach(o->{
try {
o.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}); long end = System.currentTimeMillis();
System.out.println(end-start);
System.out.println(lists.size());
}
}
高并发编程基础(java.util.concurrent包常见类基础)的更多相关文章
- Java并发编程之java.util.concurrent包下常见类的使用
一,Condition 一个场景,两个线程数数,同时启动两个线程,线程A数1.2.3,然后线程B数4.5.6,最后线程A数7.8.9,程序结束,这涉及到线程之间的通信. public class Co ...
- 【并发编程】【JDK源码】JDK的(J.U.C)java.util.concurrent包结构
本文从JDK源码包中截取出concurrent包的所有类,对该包整体结构进行一个概述. 在JDK1.5之前,Java中要进行并发编程时,通常需要由程序员独立完成代码实现.当然也有一些开源的框架提供了这 ...
- 深入理解java:2.3. 并发编程 java.util.concurrent包
JUC java.util.concurrent包, 这个包是从JDK1.5开始引入的,在此之前,这个包独立存在着,它是由Doug Lea开发的,名字叫backport-util-concurrent ...
- 线程并发线程安全介绍及java.util.concurrent包下类介绍
线程Thread,在Java开发中多线程是必不可少的,但是真正能用好的并不多! 首先开启一个线程三种方式 ①new Thread(Runnable).start() ②thread.start(); ...
- Java 并发 —— Java 标准库对并发的支持及 java.util.concurrent 包
0. Collections.synchronizedXxx() Java 中常用的集合框架中的实现类:HashSet/TreeSet.ArrayList/LinkedList.HashMap/Tre ...
- 并发之java.util.concurrent.atomic原子操作类包
15.JDK1.8的Java.util.concurrent.atomic包小结 14.Java中Atomic包的原理和分析 13.java.util.concurrent.atomic原子操作类包 ...
- 《java.util.concurrent 包源码阅读》 结束语
<java.util.concurrent 包源码阅读>系列文章已经全部写完了.开始的几篇文章是根据自己的读书笔记整理出来的(当时只阅读了部分的源代码),后面的大部分都是一边读源代码,一边 ...
- 《java.util.concurrent 包源码阅读》02 关于java.util.concurrent.atomic包
Aomic数据类型有四种类型:AomicBoolean, AomicInteger, AomicLong, 和AomicReferrence(针对Object的)以及它们的数组类型, 还有一个特殊的A ...
- java.util.concurrent包
在JavaSE5中,JUC(java.util.concurrent)包出现了 在java.util.concurrent包及其子包中,有了很多好玩的新东西: 1.执行器的概念和线程池的实现.Exec ...
随机推荐
- Flume配置Load balancing Sink Processor
1 官网内容 2 找一个图来理解一目了然 3 详细配置 配置文件load_source_case.conf 配置数据入口 source到channel 配置了两个sink用来做负载均衡 #配置文件: ...
- 区分defer和async
今天要介绍的让脚本延迟加载,让脚本延迟加载的方式有多种,最简单粗暴的方法就是将 <script> 标签放在 <body> 标签的最下面,这样就可以按照先后顺序依次执行了,但是你 ...
- 【blog】SpringBoot事务
参考链接 http://www.cnblogs.com/xingzc/p/6029483.html
- __call__
object.__call__(self[, args...]) Called when the instance is “called” as a function; if this method ...
- 2、jQuery的基本概念-必看-版本-入口函数- jq对象和dom对象区别
1.4. jQuery的版本 官网下载地址:http://jquery.com/download/ jQuery版本有很多,分为1.x 2.x 3.x 大版本分类: 1.x版本:能够兼容IE678浏览 ...
- 获取汉字拼音&首字母
pinyin4j https://www.cnblogs.com/yjq520/p/7681537.html
- dom解析xml随笔
1.dom解析jar包准备: dom解析需用到dom4j的jar包,比如我在项目中用到的的是dom4j-1.6.1jar,因为项目用的是MAVEN,所以可直接到maven中央库去搜索相关pom坐标配置 ...
- ethtool 解决网卡丢包严重和网卡原理【转】
转自:https://blog.csdn.net/u011857683/article/details/83758869 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog ...
- workqueue --最清晰的讲解
带你入门: 1.INIT_WORK(struct work_struct *work, void (*function)(void *), void *data) 上面一句只是定义了work和work ...
- python3+selenium入门13-操作cookie
可以把cookie理解为自己账户的身份证.因为http协议是无状态的,上一个请求和下一个请求没有关系.但是有时需要有关联.比如登录之后,才能进行操作这样的设置.这个就是cookie在起作用.登录成功时 ...