java并发深入
对象由数据+行为组成。数据就是字段,行为就是方法。
并发须要保证这些可被多个线程訪问的共享对象数据的完整性,以及某些特定完整性语义。
比方一个类有一个字段count=0,两个线程同一时候对它做加1操作。
这时就有可能发生:
线程1查询到count为1对其加1。
线程2查询到count为1。对其加1。
接着线程1提交。线程2提交。
终于值count还是为1。
也就是说线程1对count的改动丢失了。
解决问题。须要加锁。
java提交了内置锁syncronized。以及Lock。
内置锁syncronized,利用monitorEnter及monitorExit两条指令保证数据的可见性与原子性。
比方A类有一个字段count,默认值为0,代码例如以下:
public class A{
private int count=0;
public syncronized add(){
count++;
}
}
线程一首先调用add方法,这时会发生下面步骤:
1.线程二尝试获取在当前A实例上的锁,没有获取到则堵塞
2.获取到锁后,将count值从主存拷到当前线程工作内存。这时count为0
线程二这时运行add方法,但发现获取不到锁。这时堵塞在那边。
线程一运行完加1后。退出解锁。
这时线程二就能够获取到锁了。
并发中对于某些集合,要使它成为同步类,我们常用封装。例如以下:
class SyncMap{
Map<String,String> maps=new HashMap<String,String>();
public syncronized V put(K key, V value){
maps.put(key,value);
}
}
这样做的长处是无论底层maps有无同步。同步策略是什么,都能够安全的实现同步。
另一种实现同步的方法,即将须要同步的操作交由已经存在的同步类来做。
考虑上面的count加1操作,假设将count类型改成AtomicInteger,由AtomicInteger实现同步。原子加1操作。
atomic
===============atomic all finish,cost:247,the res:3000000
===============atomic all finish,cost:248,the res:3000000
===============atomic all finish,cost:262,the res:3000000
===============atomic all finish,cost:239,the res:3000000
===============atomic all finish,cost:249,the res:3000000
sync
===============sync all finish,cost:54,the res:3000000
===============sync all finish,cost:45,the res:3000000
===============sync all finish,cost:47,the res:3000000
===============sync all finish,cost:45,the res:3000000
===============sync all finish,cost:49,the res:3000000
測试表明上述对于300个线程,每一个线程做10000次加1操作,内置锁syncronized比atomicInteger效率要高
基本上当并发竞争某个锁非常激烈时,内置锁或者Lock比CAS效率高,原因是当竞争非常激烈时,多个线程做CAS时发现非常难成功。这样浪费了非常多CPU资源。
測试代码例如以下:
public class SyncWithAtomicTest {
private int count=0;
private static final int threadCount=300;
private static final int countNum=10000;
private final AtomicInteger countAtomicInteger=new AtomicInteger(0);
private static final ExecutorService threadPool=Executors.newFixedThreadPool(threadCount);
private final CountDownLatch latchStart=new CountDownLatch(threadCount);
private final CountDownLatch latchEnd=new CountDownLatch(threadCount);
public synchronized void addWithCountSync(){
for(int i=0;i<countNum;i++){
count++;
}
}
public void addWithAtomicCount(){
for(int i=0;i<countNum;i++){
countAtomicInteger.incrementAndGet();
}
}
public static void main(String[] args) throws InterruptedException {
SyncWithAtomicTest obj=new SyncWithAtomicTest();
Long oldTime=System.currentTimeMillis();
for(int i=0;i<threadCount;i++){
CountTask t=new CountTask();
t.setTarget(obj);
threadPool.execute(t);
}
obj.latchEnd.await();
Long endTime=System.currentTimeMillis()-oldTime;
// System.out.println("===============atomic all finish,cost:"+endTime+",the res:"+obj.countAtomicInteger.get());
System.out.println("===============sync all finish,cost:"+endTime+",the res:"+obj.count);
}
static class CountTask implements Runnable{
private SyncWithAtomicTest target;
public void run() {
try {
target.latchStart.countDown();
target.latchStart.await();
//we do add oper when all threads is ready
target.addWithCountSync();
// target.addWithAtomicCount();
System.out.println("thread:"+Thread.currentThread().getId()+",finish the work");
target.latchEnd.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
public void setTarget(SyncWithAtomicTest target) {
this.target = target;
}
}
}
java并发深入的更多相关文章
- 多线程的通信和同步(Java并发编程的艺术--笔记)
1. 线程间的通信机制 线程之间通信机制有两种: 共享内存.消息传递. 2. Java并发 Java的并发采用的是共享内存模型,Java线程之间的通信总是隐式执行,通信的过程对于程序员来说是完全透 ...
- 【Java并发编程实战】----- AQS(四):CLH同步队列
在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形.其主要从两方面进行了改造:节点的结构与节点等待机制.在结构上引入了头 ...
- 【Java并发编程实战】----- AQS(三):阻塞、唤醒:LockSupport
在上篇博客([Java并发编程实战]----- AQS(二):获取锁.释放锁)中提到,当一个线程加入到CLH队列中时,如果不是头节点是需要判断该节点是否需要挂起:在释放锁后,需要唤醒该线程的继任节点 ...
- 【Java并发编程实战】----- AQS(二):获取锁、释放锁
上篇博客稍微介绍了一下AQS,下面我们来关注下AQS的所获取和锁释放. AQS锁获取 AQS包含如下几个方法: acquire(int arg):以独占模式获取对象,忽略中断. acquireInte ...
- 【Java并发编程实战】-----“J.U.C”:CLH队列锁
在前面介绍的几篇博客中总是提到CLH队列,在AQS中CLH队列是维护一组线程的严格按照FIFO的队列.他能够确保无饥饿,严格的先来先服务的公平性.下图是CLH队列节点的示意图: 在CLH队列的节点QN ...
- 【Java并发编程实战】-----“J.U.C”:CountDownlatch
上篇博文([Java并发编程实战]-----"J.U.C":CyclicBarrier)LZ介绍了CyclicBarrier.CyclicBarrier所描述的是"允许一 ...
- 【Java并发编程实战】-----“J.U.C”:CyclicBarrier
在上篇博客([Java并发编程实战]-----"J.U.C":Semaphore)中,LZ介绍了Semaphore,下面LZ介绍CyclicBarrier.在JDK API中是这么 ...
- 【Java并发编程实战】-----“J.U.C”:ReentrantReadWriteLock
ReentrantLock实现了标准的互斥操作,也就是说在某一时刻只有有一个线程持有锁.ReentrantLock采用这种独占的保守锁直接,在一定程度上减低了吞吐量.在这种情况下任何的"读/ ...
- Java并发编程:volatile关键字解析
Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在 ...
- JAVA并发编程J.U.C学习总结
前言 学习了一段时间J.U.C,打算做个小结,个人感觉总结还是非常重要,要不然总感觉知识点零零散散的. 有错误也欢迎指正,大家共同进步: 另外,转载请注明链接,写篇文章不容易啊,http://www. ...
随机推荐
- [Linux内核]软中断与硬中断
转自:http://blog.csdn.net/zhangskd/article/details/21992933 本文主要内容:硬中断 / 软中断的原理和实现 内核版本:2.6.37 Author: ...
- SQL Server 2012附加数据库报错
操作系统: win8 数据库:SQL 2012 遇到问题: 以管理员身份登录SQL 2012,附件数据库提示如下错误: 解决办法: 以windows账号登录,附加,成功!
- 115个Java面试题和答案(上)
转自:http://www.importnew.com/10980.html 本文我们将要讨论Java面试中的各种不同类型的面试题,它们可以让雇主测试应聘者的Java和通用的面向对象编程的能力.下面的 ...
- web页面防盗链功能使用--request.getHeader("Referer")
使用Request对象设置页面的防盗链 所谓的防盗链就是当你以一个非正常渠道去访问某一个Web资源的时候,服务器会将你的请求忽略并且将你的当前请求变为按正常渠道访问时的请求并返回到相应的页面,用户只有 ...
- 【转】【C#】迭代器IEnumerable和IEnumerator
迭代器模式是设计模式中行为模式(behavioral pattern)的一个例子,他是一种简化对象间通讯的模式,也是一种非常容易理解和使用的模式.简单来说,迭代器模式使得你能够获取到序列中的所有元素而 ...
- 多媒体开发之rtp 打包发流--- 从h264中获取分辨率
http://blog.csdn.net/DiegoTJ/article/details/5541877 http://www.cnblogs.com/lidabo/p/4482684.html 分辨 ...
- "reason":"No handler for type [attachment] declared on field [file]" 最完全解决方案
0.elasticsearch-mapper-attachments 2.3.4安装 mapper-attachments安装方法分两类,在线和离线: 在线安装 bin/elasticsearch-p ...
- 判断asp.net中session过期方法的比较
重写继承page的OnInit()虚方法,在需要的界面上,继承这个类. 1.新建继承page类的类JudgeSession,实现接口成员. 2.重写OnInit()方法,判断session情况. 3. ...
- LED音乐频谱之概述
点击打开链接 转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/37929733 这个LED音乐频谱是我在学51单片机的 ...
- Hibernate_day01--解决配置文件没有提示问题_演示常见错误
解决配置文件没有提示问题 1 可以上网 2 把约束文件引入到eclipse中 (1)在配置文件中复制一句话 重启eclipse开发工具 演示常见错误 1 在映射配置文件中,把name属性值写错了,和实 ...