synchronized与条件同步
在并发编程中,有这样的需求:当满足某个条件时线程执行同步块中的代码,条件不满足时,让线程在此等待,直至条件满足再执行同步代码块。
java的Object类即提供了一类这样的方法wait(),notifyAll()/notify(),调用wait()方法后,线程A释放对同步代码块的控制并进入休眠状态,
在条件再次满足时,调用notifyAll()/notify()方法唤醒线程A,线程A将被唤醒并重新试图获得同步代码块的控制,在进入同步代码块成功之后,
再次对条件判断。
典型的应用场景是生产者-消费者模式,有一个固定大小的缓冲区存放消息,一个或者多个生产者线程把消息写入缓冲区;一个或者多个消费者从缓冲区获取消息。
如果缓冲区满了,生产者就不能写入消息,并等待。如果缓冲区为空,消费者就不能获取消息,并等待。
我们使用synchronized关键字来同步代码块,由于java中的类都继承自Object类,因此可以在我们的类中调用wait()让线程进入休眠并等待唤醒。
首先创建一个类MessageStorage来管理消息缓冲区,并使用LinkedList队列来作为消息缓冲区:
public class MessageStorage {
private int maxSize;
private List<String> messages;
public MessageStorage(int maxSize) {
this.maxSize = maxSize;
messages = new LinkedList<String>();
}
public void set(String message){
synchronized (this){
while(messages.size() == maxSize){
try {
System.out.print("the message buffer is full now,startinto wait()\n");
wait();//满足条件时,线程休眠并释放锁。当调用notifyAll()时。线程唤醒并重新获得锁
}catch (InterruptedException e){
e.printStackTrace();
}
}
try{
Thread.sleep(100);
}catch (InterruptedExceptione){
e.printStackTrace();
}
messages.add(message);
System.out.print("add message:"+message+" success\n");
notifyAll();//唤醒休眠的线程
}
}
public String get(){
String message = null;
synchronized (this){
while(messages.size() == 0){
try {
System.out.print("the message buffer is empty now,startinto wait()\n");
wait();
}catch (InterruptedExceptione){
e.printStackTrace();
}
}
try{
Thread.sleep(100);
}catch (InterruptedExceptione){
e.printStackTrace();
}
message =((LinkedList<String>)messages).poll();
System.out.print("get message:"+message+" success\n");
notifyAll();
}
return message;
}
}
实现一个生产者,向消息缓冲区写入消息:
public class Producer implements Runnable{
private MessageStorage messageStorage;
private int index;
public Producer(MessageStorage messageStorage,int index) {
this.messageStorage = messageStorage;
this.index = index;
}
public void run(){
for(int i=0; i<5; i++){
StringBuffer message = new StringBuffer("thread id:");
message.append(index);
message.append(" id:");
message.append(i);
messageStorage.set(message.toString());
}
}
}
实现一个消费者,从消息缓冲区取数据:
public class Consumer implements Runnable{
private MessageStorage messageStorage;
public Consumer(MessageStorage messageStorage) {
this.messageStorage = messageStorage;
}
public void run(){
for(int i=0; i<5; i++){
messageStorage.get();
}
}
}
测试代码:
public class ThreadMain {
public static void main(String[] args){
MessageStorage messageStorage = new MessageStorage(10);
Thread[] threads = new Thread[10];
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new Producer(messageStorage,i));//创建多个生产者
threads[i] = thread;
}
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(new Consumer(messageStorage));//创建多个消费者
threads[i+5] = thread;
}
for(int i = 0; i < 10; i++){
Thread thread = threads[i];
try {
thread.start();//启动线程
}catch (Exception e){
e.printStackTrace();
}
}
}
}
总结:
使用wait()和notifyAll()/notify()方法,便于我们在程序中主动的控制的线程的休眠和唤醒 ,实现更为复杂的逻辑控制要求。另外,我们也可以使用Lock锁来进行代码控制,使用锁的条件Condition的await()和signal()/和signalAll()控制线程的休眠、唤醒,来实现上面的生产者-消费者模型。
synchronized与条件同步的更多相关文章
- Java中的Lock锁
Lock锁介绍: 在java中可以使用 synchronized 来实现多线程下对象的同步访问,为了获得更加灵活使用场景.高效的性能,java还提供了Lock接口及其实现类ReentrantLock和 ...
- 线程高级篇-Lock锁实现生产者-消费者模型
Lock锁介绍: 在java中可以使用 synchronized 来实现多线程下对象的同步访问,为了获得更加灵活使用场景.高效的性能,java还提供了Lock接口及其实现类ReentrantLock和 ...
- java 多线程 Synchronized方法和方法块 synchronized(this)和synchronized(object)的理解
synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块. 1. synchronized 方法:通过在方法声明中加入 synchronized ...
- 单例模式中用volatile和synchronized来满足双重检查锁机制
背景:我们在实现单例模式的时候往往会忽略掉多线程的情况,就是写的代码在单线程的情况下是没问题的,但是一碰到多个线程的时候,由于代码没写好,就会引发很多问题,而且这些问题都是很隐蔽和很难排查的. 例子1 ...
- Thread 学习记录 <1> -- volatile和synchronized
恐怕比较一下volatile和synchronized的不同是最容易解释清楚的.volatile是变量修饰符,而synchronized则作用于一段代码或方法:看如下三句get代码: int i1; ...
- synchronized使用说明
好久没有更新博客了,今天试着用简单的语言把synchronized的使用说清楚. synchronized是什么? synchronized是用来保证在多线程环境下代码同步执行的可重入的互斥锁.所谓互 ...
- 【Java并发系列04】线程锁synchronized和Lock和volatile和Condition
img { border: solid 1px } 一.前言 多线程怎么防止竞争资源,即防止对同一资源进行并发操作,那就是使用加锁机制.这是Java并发编程中必须要理解的一个知识点.其实使用起来还是比 ...
- (转)Lock和synchronized比较详解
今天看了并发实践这本书的ReentantLock这章,感觉对ReentantLock还是不够熟悉,有许多疑问,所有在网上找了很多文章看了一下,总体说的不够详细,重点和焦点问题没有谈到,但这篇文章相当不 ...
- Synchronized同步性与可见性
Synchronized是具有同步性与可见性的,那么什么是同步性与可见性呢? (1)同步性:同步性就是一个事物要么一起成功,要么一起失败,可谓是有福同享有难同当,就像A有10000去银行转5000给身 ...
随机推荐
- pandas(七)数据规整化:清理、转换、合并、重塑之合并数据集
pandas对象中的数据可以通过一些内置的方式进行合并: pandas.merge 可根据一个或多个键将不同的DataFrame中的行连接起来. pandas.concat可以沿着一条轴将多个对象堆叠 ...
- www的构建技术
www的构建技术分别是: html超文本标记语言,页面的文本显示 http超文本传输协议,信息传输转移的约定 url统一资源定位符,客户端浏览超文本的地址集合
- Sevrlet 工作原理解析-转
从 Servlet 容器说起 要介绍 Servlet 必须要先把 Servlet 容器说清楚,Servlet 与 Servlet 容器的关系有点像枪和子弹的关系,枪是为子弹而生,而子弹又让枪有了杀伤力 ...
- 如何降低移动APP的开发成本
在当下竞争激烈的商业世界中,移动APP开发是您业务的有利补充.移动APP可通过吸引新客户和保留现有客户,帮助公司成功开展业务.定制一个属于自己公司的移动APP扮演着重要角色,手机APP可以说通过轻松处 ...
- Hive优化案例
1.Hadoop计算框架的特点 数据量大不是问题,数据倾斜是个问题. jobs数比较多的作业效率相对比较低,比如即使有几百万的表,如果多次关联多次汇总,产生十几个jobs,耗时很长.原因是map re ...
- CARVARS 圆形进度条
先看下效果 这是两个不同进度的进度条,由于carvas用找的只是id所以下面想多个进度条必须要根据class来找到id,所以我封装了一个进度条的函数,下面的代码直接复制粘贴就可以了 <!DOCT ...
- [LeetCode] Smallest Range 最小的范围
You have k lists of sorted integers in ascending order. Find the smallest range that includes at lea ...
- jenkins实战(一):war安装及插件安装
一:整体介绍 以下摘自维基百科: Jenkins是一个用Java编写的开源的持续集成工具.在与Oracle发生争执后,项目从Hudson项目复刻. Jenkins提供了软件开发的持续集成服务.它运行在 ...
- Python默认版本切换
Mac上自带python2.7 版本,但是我又下了一个3.7版本(下载的版本默认安装在 /Library/Frameworks/Python.framework/Versions/3.7/bin/py ...
- svg从入门到装逼(一)
svg文件是基于xml的矢量图,而canvas是基于html和js的位图.关于两者的比较,在粗就不赘述了. 1. 首先来上一个svg的基本结构: <?xml version="1.0 ...