在并发编程中,有这样的需求:当满足某个条件时线程执行同步块中的代码,条件不满足时,让线程在此等待,直至条件满足再执行同步代码块。

java的Object类即提供了一类这样的方法wait(),notifyAll()/notify(),调用wait()方法后,线程A释放对同步代码块的控制并进入休眠状态,

在条件再次满足时,调用notifyAll()/notify()方法唤醒线程A,线程A将被唤醒并重新试图获得同步代码块的控制,在进入同步代码块成功之后,

再次对条件判断。

典型的应用场景是生产者-消费者模式,有一个固定大小的缓冲区存放消息,一个或者多个生产者线程把消息写入缓冲区;一个或者多个消费者从缓冲区获取消息。

如果缓冲区满了,生产者就不能写入消息,并等待。如果缓冲区为空,消费者就不能获取消息,并等待。

我们使用synchronized关键字来同步代码块,由于java中的类都继承自Object类,因此可以在我们的类中调用wait()让线程进入休眠并等待唤醒。

首先创建一个类MessageStorage来管理消息缓冲区,并使用LinkedList队列来作为消息缓冲区:

  1. public class MessageStorage {
  2. private int maxSize;
  3. private List<String> messages;
  4.  
  5. public MessageStorage(int maxSize) {
  6. this.maxSize = maxSize;
  7. messages = new LinkedList<String>();
  8. }
  9. public void set(String message){
  10. synchronized (this){
  11. while(messages.size() == maxSize){
  12. try {
  13. System.out.print("the message buffer is full now,startinto wait()\n");
  14. wait();//满足条件时,线程休眠并释放锁。当调用notifyAll()时。线程唤醒并重新获得锁
  15. }catch (InterruptedException e){
  16. e.printStackTrace();
  17. }
  18. }
  19. try{
  20. Thread.sleep(100);
  21. }catch (InterruptedExceptione){
  22. e.printStackTrace();
  23. }
  24. messages.add(message);
  25. System.out.print("add message:"+message+" success\n");
  26. notifyAll();//唤醒休眠的线程
  27. }
  28. }
  29. public String get(){
  30. String message = null;
  31. synchronized (this){
  32. while(messages.size() == 0){
  33. try {
  34. System.out.print("the message buffer is empty now,startinto wait()\n");
  35. wait();
  36. }catch (InterruptedExceptione){
  37. e.printStackTrace();
  38. }
  39. }
  40. try{
  41. Thread.sleep(100);
  42. }catch (InterruptedExceptione){
  43. e.printStackTrace();
  44. }
  45. message =((LinkedList<String>)messages).poll();
  46. System.out.print("get message:"+message+" success\n");
  47. notifyAll();
  48. }
  49. return message;
  50. }
  51. }

实现一个生产者,向消息缓冲区写入消息:

  1. public class Producer implements Runnable{
  2. private MessageStorage messageStorage;
  3. private int index;
  4. public Producer(MessageStorage messageStorage,int index) {
  5. this.messageStorage = messageStorage;
  6. this.index = index;
  7. }
  8.  
  9. public void run(){
  10. for(int i=0; i<5; i++){
  11. StringBuffer message = new StringBuffer("thread id:");
  12. message.append(index);
  13. message.append(" id:");
  14. message.append(i);
  15. messageStorage.set(message.toString());
  16. }
  17. }
  18. }

实现一个消费者,从消息缓冲区取数据:

  1. public class Consumer implements Runnable{
  2. private MessageStorage messageStorage;
  3. public Consumer(MessageStorage messageStorage) {
  4. this.messageStorage = messageStorage;
  5. }
  6.  
  7. public void run(){
  8. for(int i=0; i<5; i++){
  9. messageStorage.get();
  10. }
  11. }
  12. }

测试代码:

  1. public class ThreadMain {
  2. public static void main(String[] args){
  3. MessageStorage messageStorage = new MessageStorage(10);
  4. Thread[] threads = new Thread[10];
  5. for (int i = 0; i < 5; i++) {
  6. Thread thread = new Thread(new Producer(messageStorage,i));//创建多个生产者
  7. threads[i] = thread;
  8. }
  9. for (int i = 0; i < 5; i++) {
  10. Thread thread = new Thread(new Consumer(messageStorage));//创建多个消费者
  11. threads[i+5] = thread;
  12. }
  13. for(int i = 0; i < 10; i++){
  14. Thread thread = threads[i];
  15. try {
  16. thread.start();//启动线程
  17. }catch (Exception e){
  18. e.printStackTrace();
  19. }
  20. }
  21. }
  22. }

总结:

使用wait()和notifyAll()/notify()方法,便于我们在程序中主动的控制的线程的休眠和唤醒 ,实现更为复杂的逻辑控制要求。另外,我们也可以使用Lock锁来进行代码控制,使用锁的条件Condition的await()和signal()/和signalAll()控制线程的休眠、唤醒,来实现上面的生产者-消费者模型。

synchronized与条件同步的更多相关文章

  1. Java中的Lock锁

    Lock锁介绍: 在java中可以使用 synchronized 来实现多线程下对象的同步访问,为了获得更加灵活使用场景.高效的性能,java还提供了Lock接口及其实现类ReentrantLock和 ...

  2. 线程高级篇-Lock锁实现生产者-消费者模型

    Lock锁介绍: 在java中可以使用 synchronized 来实现多线程下对象的同步访问,为了获得更加灵活使用场景.高效的性能,java还提供了Lock接口及其实现类ReentrantLock和 ...

  3. java 多线程 Synchronized方法和方法块 synchronized(this)和synchronized(object)的理解

    synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块. 1. synchronized 方法:通过在方法声明中加入 synchronized ...

  4. 单例模式中用volatile和synchronized来满足双重检查锁机制

    背景:我们在实现单例模式的时候往往会忽略掉多线程的情况,就是写的代码在单线程的情况下是没问题的,但是一碰到多个线程的时候,由于代码没写好,就会引发很多问题,而且这些问题都是很隐蔽和很难排查的. 例子1 ...

  5. Thread 学习记录 <1> -- volatile和synchronized

    恐怕比较一下volatile和synchronized的不同是最容易解释清楚的.volatile是变量修饰符,而synchronized则作用于一段代码或方法:看如下三句get代码: int i1;  ...

  6. synchronized使用说明

    好久没有更新博客了,今天试着用简单的语言把synchronized的使用说清楚. synchronized是什么? synchronized是用来保证在多线程环境下代码同步执行的可重入的互斥锁.所谓互 ...

  7. 【Java并发系列04】线程锁synchronized和Lock和volatile和Condition

    img { border: solid 1px } 一.前言 多线程怎么防止竞争资源,即防止对同一资源进行并发操作,那就是使用加锁机制.这是Java并发编程中必须要理解的一个知识点.其实使用起来还是比 ...

  8. (转)Lock和synchronized比较详解

    今天看了并发实践这本书的ReentantLock这章,感觉对ReentantLock还是不够熟悉,有许多疑问,所有在网上找了很多文章看了一下,总体说的不够详细,重点和焦点问题没有谈到,但这篇文章相当不 ...

  9. Synchronized同步性与可见性

    Synchronized是具有同步性与可见性的,那么什么是同步性与可见性呢? (1)同步性:同步性就是一个事物要么一起成功,要么一起失败,可谓是有福同享有难同当,就像A有10000去银行转5000给身 ...

随机推荐

  1. 框架学习笔记之Mybatis(二)

    一.动态sql 通过mybatis提供的标签,实现sql语句的拼接. 1.where <select id="findUserList" parameterType=&quo ...

  2. js正则表达式入门以及常见用例

    学习正则表达式的最好方法是从例子开始,理解例子之后再自己对例子进行修改,实验.下面给出了不少简单的例子,并对它们作了详细的说明. 假设你在一篇英文小说里查找hi,你可以使用正则表达式hi. 这几乎是最 ...

  3. JSON序列化类

    '''pyhton的dict对象可以直接序列化为JSON的{},不过很多时候 我们更喜欢用class表示对象,比如定义Student类,然后序列化''' import json class Stude ...

  4. 【webstorm使用手册】如何安装插件

    Files->Settings, 搜索"plugin",如图,

  5. mysql之连接查询小作业

    #数据准备drop table if exists class;create table class(    class_no int(2) unsigned zerofill primary key ...

  6. js获取设备

    总结了一个JavaScript获取当前终端类型(pc, mobile),操作系统类型,浏览器类型,浏览器版本的小工具. 个人觉得还行,测试过没有问题,能识别ie7以及以上. 1 2 3 4 5 6 7 ...

  7. [ZJOI 2006]超级麻将

    Description Input 第一行一个整数N(N<=100),表示玩了N次超级麻将. 接下来N行,每行100个数a1..a100,描述每次玩牌手中各种牌的数量.ai表示数字为i的牌有ai ...

  8. [SDOI 2008]仪仗队

    Description 作为体育委员,C君负责这次运动会仪仗队的训练.仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是 ...

  9. 内存管理——linux内核学习

    买了<深入Linux内核架构>这本书准备了解一下linux内核机制.但是最开始看了十几页感觉看着很累,本来都准备弃了 过了段时间看见一个面经有linux内核的内容,于是就照着那个先把内存管 ...

  10. hdu 2296 aC自动机+dp(得到价值最大的字符串)

    Ring Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...