java 多线程协作肯定因为共享对象,实现原理是基于线程挂起和线程恢复。
wait notify condition 都是 基于锁对象产生的衍生方法,多线程之间可以依靠这些方法实现线程协作。
synchronized 的锁原理是在共享对象头里添加标记和对象监控器,这些都是jvm 内部实现的。
而 lock 的锁原理是 独立于共享对象之外 新建一个锁监控对象(锁对象就类似于synchronized 的monitor),需要用户自定义。
synchronized 底层通过monitor 来存储共享对象的并发使用情况,多个线程之间可以通过使用 共享对象.wait 和 共享对象.notify 来实现 多线程 切换。
Lock 也可以实现Object中的notify与wait功能,那就是:Condition
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();//多线程操作共享对象使用的锁。
当使用如下的方法就相当于使用Object类的 wait
condition.await();
使用如下方法相当于使用Object类的 notify
condition.signal();
synchronized 和wait notify 的使用:
List list=new Arraylist();//共享对象。
synchronized String get(){
if(CollectionUtils.isnotempty(list)){
list.notify();
return list.get(0);
}else{
list.wait();
}
}
synchronized String set(){
if(CollectionUtils.isnotfull(list)){
list.add("asdasd);
list.notify();
} else{
list.wait();
}
}
Lock 和 Condition 的使用
List list=new Arraylist(); //共享对象。
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();/
String get(){
lock.lock();
try{
if(CollectionUtils.isnotempty(list)){
condition.signal(); return list.get(0);
}else{condition.await() }
}catch(Exception e){
catch exception...
}finally{
lock.unlock();
}
}
String set(){
lock.lock();
try{
if(CollectionUtils.isnotfull(list)){
condition.signal(); list.add("ssda);
}else{condition.await() }
}catch(Exception e){
catch exception...
}finally{
lock.unlock();
}
}
以上是如果只有一个读线程和一个写线程的情况下,我们可以这样处理,但是如果有 多个读线程,多个写线程,
如果写的时候发现满了,想要唤醒读线程,但是 notify根本不知道自己唤醒的是读线程,还是写线程。这时候我们就可以用condition 实现了,同一个lock 上可以建立 多个condition ,代码优化如下:
List list=new Arraylist(); //共享对象。
private Lock lock = new ReentrantLock();
private Condition read = lock.newCondition();/
private Condition write = lock.newCondition();/
String get(){
lock.lock();
try{
if(CollectionUtils.isnotempty(list)){
if(list.size==1){ write.signal()}
return list.get(0);
}else{read.await()}
}catch(Exception e){
catch exception...
}finally{
lock.unlock();
}
}
String set(){
lock.lock();
try{
if(CollectionUtils.isnotfull(list)){
if(list.size==maxsize){ read.signal()}
list.add("ssda);
}else{write.await()}
}catch(Exception e){
catch exception...
}finally{
lock.unlock();
}
}
对象监视器里的队列分为 等待队列 和正在处理的 队列,正在处理的队列处理完之后发送一个信号通知到等待队列,等待队列的线程收到消息开始处理。
之前使用wait 和notify 实现,但是以上说明了 缺点,当多个读和写线程都在等待的时候,并不能确定唤醒的是哪种线程。
现在用condition 可以把 读队列和写队列 分开,分成了2个队列。通知的时候也只要通知特定队列的线程就可以了。
condition 就是 阻塞线程分组的依据。一部分线程在等待读操作,一部分线程在等待写操作。