并发入门
2016-05-22 18:12
148 查看
引例
如下:private int a; private void test() { ExecutorService pool = Executors.newFixedThreadPool(10); for(int x = 0;x<10;x++){ pool.execute(new Runnable() { @Override public void run() { log(); } }); } } private void log(){ a++; Thread.yield(); a++; Log.e("TAST","a = "+a+",currentThread ="+ Thread.currentThread()); }
在上面代码中,正常逻辑下, 每一次输出的应该都是偶数。但涉及多线程时,有些时候会输出奇数。
yield()
当前线程释放CPU资源,由CPU随机选择一个线程执行——有可能是调用yield()方法的线程。上述代码中调用yield()的主要作用就是调用可能存在的并发问题暴露的机率。原因
多个线程访问同一共享性资源,而共享性资源又非原子性操作(如赋值,返回这样的操作是无法打断的,称它们具有原子性,而a++方法是可能被打断的,所以非原子性)。上述代码中,多个线程调用了同一个log()方法,这个log()方法就是共享性资源。
synchronized
修饰方法时:为方法加锁,这样该方法同时只能被一个线程进行操作。同一个对象中,所以sync方法共用同一个锁,一个线程可以多次获取一个对象的锁,因此多个线程也只有一次调用该对象中一个方法。例如t1,t2为两个线程,前者访问sync方法f1,后者访问sync方法f2。如果t1先执行且未执行完毕之前,t2是无法访问到f2的。因为f1与f2的锁一致,t1访问时该锁被锁上了。但t1可以再访问f2。可以使用sync对上述代码中的log进行修饰加锁,就会避免并发问题。
Lock
lock必须被显式的创建、加锁与释放。如,private void log(){ lock.lock();//lock是ReentrantLock try{ a++; Thread.yield(); a++; Log.e("TAST","a = "+a+",currentThread ="+ Thread.currentThread()); }finally { lock.unlock(); } }
上述代码中,在finally()中调用lock#unlock()。这就保证了必须会调用到unlock()。
有一点要注意:如果该方法有返回值的话, 必须放在try中写,用于确保return语句不会过早发生,从而将结果暴露给别的线程。
常用方法
tryLock():尝试获取锁,如果能获取成功就立即返回true,如果不能获取成功就立即返回false。tryLock(long,TimeUnit):在指定的时间内如果能获取锁,就返回true,否则返回false。在此过程中,会被intercept掉。
比较
与sync类似,都是用来进行加锁处理同步问题的。但使用sync关键字,代码更少,并且出错的可能性也会降低。因此通常只在解决特殊问题的时候才使用lock。使用lock,使程序拥有更细粒度的控制力。还允许尝试获取锁——结果不一定能获取到。并且在锁内部如果出现异常,还可以在finally中进行清理操作。
相关文章推荐
- 第十二周进度条
- [置顶] 组合数学各种小定理
- 页面未随软键盘上升及android隐藏软键盘总结
- c++上机实验6-项目3-矩阵求和
- newLISP运行scp命令并打印进度
- HDU 5699 货物运输 (二分 + 不等式判断 好题)
- Machine Learning - Andrew NG Class02 - 监督学习应用.梯度下降
- vim 格式化文本,调整缩进
- ATL一:CWindowImpl
- CodeForces 23A-You're Given a String...
- iptables超详细解读
- Hdu5696 区间的价值(花式水)
- 动态规划:最长公共子串长度
- 第12课:Spark Streaming源码解读之executor容错安全性
- 百度之星 初赛2 瞬间转移 [杨辉三角]
- 第11课:Spark Streaming源码解读之Driver中的ReceiverTracker架构设计以及具体实现彻底研究
- bond科普
- Arch LInux 系统迁移
- innodb_flush_log_at_trx_commit不同参数值下的性能测试
- LaTeX新人教程,30分钟从完全陌生到基本入门