并发入门
来源:互联网 发布:优酷网络剧燃血女神 编辑:程序博客网 时间:2024/06/05 17:50
引例
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中进行清理操作。
- 并发入门
- 并发编程网-并发入门
- python 并发编程入门
- java并发编程入门
- 高并发程序设计入门
- 高并发程序设计入门
- 高并发程序设计入门
- 高并发程序设计入门
- 高并发程序设计入门
- 高并发程序设计入门
- 【同步并发】入门小结
- 并发编程Disruptor入门
- Actor并发模型入门
- 【C++】并发编程入门
- 高并发程序设计入门
- 高并发程序设计入门
- Disruptor并发框架入门
- Web并发模型入门
- Oracle开发实战-字符函数
- 如何退出一个app
- 人生,青春
- Redis
- 课程练习三-1007-problem G
- 并发入门
- 点-园-圆柱类族的设计
- Linus
- 实用知识:指纹识别功能的实现
- 学习SpringMVC(十四)之关于重定向
- Your Ride Is Here
- 硬件焊接
- c++作业六
- 存储班长信息的学生类