转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6556925.html 

一:syncrhoized使用同一把锁的多个线程用通信实现执行顺序的调度

我们知道,使用syncrhoized关键字修饰一个代码块、一个方式时,在代码块、方法执行完毕之前是不会释放掉所持有的锁的,在执行期间,其他申请这个锁的线程只能阻塞等待。这些等待的线程被安排在一个等待队列中。

现在,由于某种原因,在当前同步代码块A中需要另一个同步代码块B先执行完,然后A才能继续进行下去。而同步代码块B是另一个线程来执行的,并且申请的是同一个同步锁。此时,就需要在A中把锁让出去并且让A线程挂起(即让出CPU,进入等待队列)【通过wait()方法挂起线程,进入该同步锁的等待队列】。B在获得同步锁并且执行完后,则通过 notify()/notifyAll() 方法唤醒该同步锁的等待队列中的线程。A被唤醒后就由等待队列中弹出,进入就绪态,等待获取CPU使用权继续执行。

二:ReentrantLock加锁的线程之间的通信实现执行调度

ReentrantLock加锁的线程是通过Condition对象的await()、signal()/signalAll()方法来挂起当前线程(挂起前先调用lock.unlock()释放掉锁),唤醒相应线程(在某condition条件下等待的线程)先执行来实现的。

Condition的最大改进在于:更加精确地进行调度。当前线程可以显式定义在某处“因何情况而等待”,也可以在释放锁后某处显式地通知“因何情况而等待的线程可以启动继续执行了”。而不再是笼统地申请同一把锁的等待线程全部启动。

我们来看一下官方提供的例子:

package locks;
import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class AppOfficial { /**
* BoundedBuffer 是一个定长100的集合,当集合中没有元素,take方法需要等待,直到有元素时才返回元素
* 当集合满了,要等待直到元素被take之后才执行put的操作
*/
static class BoundedBuffer {
//定义一个锁对象
final Lock lock = new ReentrantLock();
//定义两种被唤醒的条件:非满、非空
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100];
int putptr, takeptr, count; public void put(Object x) throws InterruptedException {
System .out.println("put wait lock");
//加锁进行put操作
lock.lock();
System.out.println("put get lock");
try {
//当集合满了,则等待 非满 情况的发生
while (count == items.length) {
System.out.println("buffer full, please wait"); //在 非满 条件下挂起,等待非满条件的唤醒操作才继续执行下去
notFull.await();
} items[putptr] = x;
if (++putptr == items.length)
putptr = 0;
++count;
//执行完插入操作后,集合非空,通知 非空 条件下挂起的线程 可以继续进行take操作了
notEmpty.signal();
} finally {
lock.unlock();
}
} public Object take() throws InterruptedException {
System.out.println("take wait lock");
lock.lock();
System.out.println("take get lock");
try {
while (count == 0) {
System.out.println("no elements, please wait");
//在 非空 条件下挂起
notEmpty.await();
}
Object x = items[takeptr];
if (++takeptr == items.length)
takeptr = 0;
--count;
//集合不是满的了,唤醒在 非满 情况下挂起的put线程可以继续执行put操作
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
} public static void main(String[] args) {
final BoundedBuffer boundedBuffer = new BoundedBuffer(); Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("t1 run");
for (int i=0;i<1000;i++) {
try {
System.out.println("putting..");
boundedBuffer.put(Integer.valueOf(i));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }) ; Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i=0;i<1000;i++) {
try {
Object val = boundedBuffer.take();
System.out.println(val);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }) ; t1.start();
t2.start();
}
}

【Java多线程通信】syncrhoized下wait()/notify()与ReentrantLock下condition的用法比较的更多相关文章

  1. java多线程15 :wait()和notify() 的生产者/消费者模式

    什么是生产者/消费者模型 一种重要的模型,基于等待/通知机制.生产者/消费者模型描述的是有一块缓冲区作为仓库,生产者可将产品放入仓库,消费者可以从仓库中取出产品,生产者/消费者模型关注的是以下几个点: ...

  2. JAVA多线程通信

    JAVA多线程通信 package com.frank.thread; /** * author:pengyan * date:Jun 16, 2011 * file:ProducerAndCusto ...

  3. java多线程通信方式之一:wait/notify

    java多线程之间的通信方式有多种: 1.wait(),notify(),notifyAll()方法;2.join()方法;3.通过volatile共享内存的方式进行线程通信的;4.interrupt ...

  4. java基础知识回顾之java Thread类学习(八)--java多线程通信等待唤醒机制经典应用(生产者消费者)

     *java多线程--等待唤醒机制:经典的体现"生产者和消费者模型 *对于此模型,应该明确以下几点: *1.生产者仅仅在仓库未满的时候生产,仓库满了则停止生产. *2.消费者仅仅在有产品的时 ...

  5. Java多线程:线程状态以及wait(), notify(), notifyAll()

    一. 线程状态类型1. 新建状态(New):新创建了一个线程对象.2. 就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中,变得可运 ...

  6. java多线程 21 : ReentrantReadWriteLock ,synchronized和ReentrantLock的对比

    读写锁ReentrantReadWriteLock概述 大型网站中很重要的一块内容就是数据的读写,ReentrantLock虽然具有完全互斥排他的效果(即同一时间只有一个线程正在执行lock后面的任务 ...

  7. java基础知识回顾之java Thread类学习(七)--java多线程通信等待唤醒机制(wait和notify,notifyAll)

    1.wait和notify,notifyAll: wait和notify,notifyAll是Object类方法,因为等待和唤醒必须是同一个锁,不可以对不同锁中的线程进行唤醒,而锁可以是任意对象,所以 ...

  8. Java多线程8:wait()和notify()/notifyAll()

    轮询 线程本身是操作系统中独立的个体,但是线程与线程之间不是独立的个体,因为它们彼此之间要相互通信和协作. 想像一个场景,A线程做int型变量i的累加操作,B线程等待i到了10000就打印出i,怎么处 ...

  9. java多线程14 :wait()和notify()/notifyAll()

    轮询 线程本身是操作系统中独立的个体,但是线程与线程之间不是独立的个体,因为它们彼此之间要相互通信和协作. 想像一个场景,A线程做int型变量i的累加操作,B线程等待i到了10000就打印出i,怎么处 ...

随机推荐

  1. SQL 常用的判断、连表、跨库、去重、分组、ROW_NUMBER()分析函数SQL用法

    常用的SQL 由浅入深 大致上回想一下自己常用的SQL,并做个记录,目标是实现可以通过在此页面查找到自己需要的SQL ,陆续补充    有不足之处,请提醒改正 首先我创建了两个库,每个库两张表.(工作 ...

  2. 关于EF中出现FOREIGNKEY约束可能会导致循环或多重级联路径的问题

    ef中,我们创建外键的时候需要注意,否则会出现标题所示问题. 例:有项目表,项目收藏表,用户表 项目表有如下字段:ProjectId,InputPersonId等 项目收藏表有如下字段:Project ...

  3. Git Extensions 和 Tortoisegit 到底是什么?Git For VS(Git For Visual Studio)(Visual Studio 中使用 Git)

    前言: 我们使用 Git 作为版本控制的朋友们,一定都熟悉 Git Extensions 和 Tortoisegit 两款工具,但是对于初学者,可能就不那么了解了. 当然如果有幸,你接触过 SVN , ...

  4. 推荐数据库、Web、Net、架构的PDF数据,书不在多,在看!

    先收藏,后看:千万不要做一个屯书的人,一定要坚持有选择性的看下去: 数据库类 SqlServer Oracle .NET  更多... Web  更多... 架构 不刮了,直接可以看到了. 链接: h ...

  5. mysql表名作为参数传入存储过程

    有以下存储过程: CREATE DEFINER=`root`@`localhost` PROCEDURE `P_HoverTreePages`( ), ) , ), ), ), IN `SortTyp ...

  6. Windows server 2008 R2端口转发

    查询配置了转发的端口 netsh interface portproxy show v4tov4 配置转发(所有ip访问192.168.0.99的1001端口均指向1953端口) netsh inte ...

  7. nginx常用命令参数

    命令行参数: 常用命令: -c filename:设置配置文件. -t :不运行,而仅仅测试配置文件.nginx 将检查配置文件的语法的正确性,并尝试打开配置文件中所引用到的文件. -s :传递一个信 ...

  8. Spring Security Oauth2 示例

    所有示例的依赖如下(均是SpringBoot项目) pom.xml <dependencies> <dependency> <groupId>org.springf ...

  9. sqlserver 2008R2新建数据库时报错,提示无法获得数据库"model"上的排它锁

    刚新装了个sqlserver2008 R2,在建立数据库时候报错,提示无法获得数据库"model"上的排它锁.解决办法如下: 打开查询页面,执行下面的语句即可. use maste ...

  10. JVM-String.intern()

    故事起源于书籍<深入理解Java虚拟机>,案例如下: public class RunTimeConstantPoolOOM { public static void main(Strin ...