对象由数据+行为组成。数据就是字段,行为就是方法。

并发须要保证这些可被多个线程訪问的共享对象数据的完整性,以及某些特定完整性语义。

比方一个类有一个字段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;
}
} }

最新文章

  1. 解决IE7和IE6不支持javaScript中的indexOf函数的问题
  2. 多通道(Multichannel)单通道(singlechannel)图像概念梳理
  3. solr 范围查询
  4. Junit4.12、Hamcrest1.3、Eclemma的安装和使用
  5. JS数组处理
  6. 每天一个linux命令(35)--free命令
  7. POI操作Excel的API注意点总结
  8. Scala:枚举类型的用法
  9. 学习python第二天
  10. spring学习(四) ———— 整合web项目(SSH)
  11. php随手记
  12. (7)MySQL的事务
  13. 解决openwrt中文界面异常
  14. mac item2 ssh
  15. mysql 配置MHA
  16. Luogu P3957 跳房子
  17. LoadRunner监控mysql利器-SiteScope(转)
  18. 2018.09.27 codeforces618F. Double Knapsack(抽屉原理+构造)
  19. phpstrom快捷键
  20. 2017 Multi-University Training Contest - Team 4——HDU6069&amp;&amp;Counting Divisors

热门文章

  1. C语言 &#183; 排列数
  2. gpio 灯的对应关系
  3. 使用shell读取文本文件发送到kafka
  4. 编译Spark2.1.2源码
  5. 树形dp - BNU 39572 Usoperanto
  6. Nginx服务器防止被压力测试
  7. ssh免密码登录的几个注意事项
  8. Excel随机生成数据2
  9. Windows下安装Apache 2.2.21图文教程
  10. 杂记之--苹果4s手机呼叫转移怎么设置