
本文可作为传智播客《张孝祥-Java多线程与并发库高级应用》的学习笔记。
上面我们说了Lock,那是对synchronized的一种更为面向对象的替代,在原来的synchronized内部,我们可以调用object的wait与notify方法,那么使用lock之后,如何进行线程的通信呢。
对锁不清楚的朋友可以看看
http://blog.csdn.net/dlf123321/article/details/42919085
答案是condition。
condition一方面是对lock功能的补充(也就是说,你用了lock,为了保证线程的通信,就得用condition)
另一方面,synchronized的notifyall是唤醒所有等待的线程,那么如果有些线程我不想唤醒呢。
看下面这个例子
主线程运行10次,然后子线程2运行20次,接着子线程3运行30次
上面的整体运行4次。
我们分析一下,主线程运行10次之后,下面一方面让自己阻塞,同时应该唤醒子线程2,并且不能唤醒子线程3。
如果用notifyAll就等于把线程2与线程3都唤醒了。
我们在这里说明一下
Reentrantlock相比较于synchronized还少有三个优势
1 等待可中断 具体的例子参考 http://uule.iteye.com/blog/1488356
2 实现公平锁 就是线程a在操作某个对象,线程b,c,d后面又依次来了,如果是非公平锁,那么等a结束后,bcd接手的概率是一样的,如果是公平锁那么a完了之后就是b
synchronized是非公平的是,Reentrantlock默认情况下也是非公平的,但可以通过有带Boolean只的构造函数构建一个公平锁
3 绑定多个条件 也就是下面讲的
4 有三种使用方式
a) lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁
b) tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;
c)tryLock(long timeout,TimeUnit unit), 如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;
参考资料 http://houlinyan.iteye.com/blog/1112535
另外我得说明一点
就性能来说,在java6之后,reentrantlock与synchronized已经差不多了
而且Reentrantlock得主动释放
所有到底选择哪个实现互斥,大家还是得考虑一下
看看方法
常用的就是await与signal。
这个两个就刚好对应object的wait与notify。
我们看代码:
package cn.itcast.heima2; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ThreeConditionCommunication { /** * @param args */ public static void main(String[] args) { final Business business = new Business(); new Thread( new Runnable() { @Override public void run() { for(int i=1;i<=4;i++){ business.sub2(i); } } } ).start(); new Thread( new Runnable() { @Override public void run() { for(int i=1;i<=4;i++){ business.sub3(i); } } } ).start(); for(int i=1;i<=4;i++){ business.main(i); } } static class Business { Lock lock = new ReentrantLock(); Condition condition1 = lock.newCondition(); Condition condition2 = lock.newCondition(); Condition condition3 = lock.newCondition(); private int shouldSub = 1; public void sub2(int i){ lock.lock(); try{ while(shouldSub != 2){ try { condition2.await(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } for(int j=1;j<=20;j++){ System.out.println("sub2 thread sequence of " + j + ",loop of " + i); } shouldSub = 3; condition3.signal(); }finally{ lock.unlock(); } } public void sub3(int i){ lock.lock(); try{ while(shouldSub != 3){ try { condition3.await(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } for(int j=1;j<=30;j++){ System.out.println("sub3 thread sequence of " + j + ",loop of " + i); } shouldSub = 1; condition1.signal(); }finally{ lock.unlock(); } } public void main(int i){ lock.lock(); try{ while(shouldSub != 1){ try { condition1.await(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } for(int j=1;j<=10;j++){ System.out.println("main thread sequence of " + j + ",loop of " + i); } shouldSub = 2; condition2.signal(); }finally{ lock.unlock(); } } } }