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给身 ...
随机推荐
- 谈谈spring-boot不同包结构下,同样的类名冲突导致服务启动失败解决方案
项目背景: 某日,有需求要在三天的时间内完成两个大项目的项目合并,因为之前两个项目的包结构和类名都很多相同,于是开始考虑使用加一级包进行隔离,类似于这种结构 但是在启动的过程中,抛出来这样的异常: C ...
- Collections、Arrays 简明
Collections : 它的出现给集合操作提供了更多的功能.这个类不需要创建对象,内部提供的都是静态方法. 一般方法 Collections. sort (list); list 集合进行元素的自 ...
- Java内存回收机制.md
1.java的内存 java的内存结构分为 堆 (是gc的主要区域) 线程共享,主要是用于分配实例对象和数组 栈 线程私有,它的生命周期和线程相同,又分成 虚拟机栈和本地方法栈,只有它会报 Stack ...
- C#之读写压缩文件
在处理文件时,常常会发现文件中有许多空格,耗尽了硬盘空间,.net的类提供了GZIP/Deflate算法可以压缩文件.这里只介绍了文件的压缩,但在实际应用更多的是压缩文件夹 压缩文件 解压文件 可以使 ...
- [LeetCode] Minesweeper 扫雷游戏
Let's play the minesweeper game (Wikipedia, online game)! You are given a 2D char matrix representin ...
- 使用IntelliJ IDEA的小技巧快乐编程(1)
前言 我很喜欢和别人讨论一些问题,有时候,在公司里,讨论这样的问题需要演示代码.常常会碰到的一种情况是(根据我的记忆这半年多来至少超过了10次),别人会打断你的演示,抛出一个问题:等等,你刚才的操作是 ...
- 解决IOS移动端 Safari流浪器 onclick无法触发的问题
在移动端布局的时候, 在底部有一个button, 页面超过两屏, 是一个可滚动的的网页, 当运行在移动端Safari浏览器上的时候, 向下滑动页面, 浏览器的头部和尾部会自动隐藏, 这样可视区域就会变 ...
- servlet之session设置
商品对象,购物车对象,servlet的实现 商品: package app02d;public class Product { private int id; private String ...
- Java爬虫原理分析
当我们需要从网络上获取资源的时候,我们一般的做法就是通过浏览器打开某个网站,然后将我们需要的东西下载或者保存下来. 但是,当我们需要大量下载的时候,这个时候通过人工一个个的去点击下载,就显得太没有效率 ...
- [SCOI2012]滑雪与时间胶囊
题目描述 a180285非常喜欢滑雪.他来到一座雪山,这里分布着MMM条供滑行的轨道和NNN个轨道之间的交点(同时也是景点),而且每个景点都有一编号iii(1≤i≤N1 \le i \le N1≤i≤ ...