java同步代码(synchronized)中使用BlockingQueue
说起BlockingQueue,大家最熟悉的就是生产者-消费者模式下的应用。但是如果在调用queue的上层代码加了同步块就会导致线程死锁。
例如:
static BlockingQueue<String> queue = new LinkedBlockingQueue();
/**
* 同步锁
*/
static Object lock = new Object();
static void producer(){
synchronized (lock){
queue.put("1");
}
}
static void cosumer(){
synchronized (lock){
//一旦阻塞,将挂起当前线程,lock锁永远等不到释放,生产者也就无法添加元素,take也就永远阻塞
String msg = queue.take();
}
}
但是同步块必须使用的情况下,怎样改进queue的使用呢?见下面示例:
package com.hdwang; import com.alibaba.fastjson.JSON; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; /**
* Created by hdwang on 2018/4/17.
*/
public class MultiQueueSynTest { static BlockingQueue<Packet> queue1 = new LinkedBlockingQueue(); static BlockingQueue<Packet> queue2 = new LinkedBlockingQueue(); static int seq = 1; /**
* 同步锁
*/
static Object lock = new Object(); static void commit(String msg){
synchronized (lock) {
Packet packet = new Packet();
packet.setSeq(seq++);
packet.setMsg(msg);
try { //queue1.put(packet); //阻塞式添加元素 while(queue1.size()== Integer.MAX_VALUE){ //队满,等待
lock.wait();
} queue1.offer(packet); //非阻塞式添加元素即可
System.out.println("commit msg:" + JSON.toJSONString(packet));
lock.notifyAll(); //通知等待线程 } catch (InterruptedException e) {
e.printStackTrace();
}
}
} static void send(){
while(true) {
synchronized (lock) {
try { //Packet packet = queue1.take(); //阻塞式取元素
//queue2.put(packet); while(queue1.isEmpty()) { //队空,等待
lock.wait(); //等待,交出锁
} Packet packet = queue1.poll(); //非阻塞式取元素即可
System.out.println("send msg:" + JSON.toJSONString(packet));
lock.notifyAll(); //通知等待线程 while (queue2.size() == Integer.MAX_VALUE){ //队满,等待
lock.wait(); //等待,交出锁
}
queue2.offer(packet);
System.out.println("msg->queue2:"+JSON.toJSONString(packet));
lock.notifyAll(); //通知等待线程 } catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} public static void main(String[] args) {
//生产者1
new Thread(new Runnable() {
@Override
public void run() {
while(true){ //不断产生消息
commit("hello1"); try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
//生产者2
new Thread(new Runnable() {
@Override
public void run() {
while(true){ //不断产生消息
commit("hello2"); try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start(); //消费者
new Thread(new Runnable() {
@Override
public void run() { send();
}
}).start(); } static class Packet{
int seq;
String msg; public int getSeq() {
return seq;
} public void setSeq(int seq) {
this.seq = seq;
} public String getMsg() {
return msg;
} public void setMsg(String msg) {
this.msg = msg;
}
} }
运行结果
commit msg:{"msg":"hello1","seq":1}
send msg:{"msg":"hello1","seq":1}
msg->queue2:{"msg":"hello1","seq":1}
commit msg:{"msg":"hello2","seq":2}
send msg:{"msg":"hello2","seq":2}
msg->queue2:{"msg":"hello2","seq":2}
commit msg:{"msg":"hello1","seq":3}
send msg:{"msg":"hello1","seq":3}
msg->queue2:{"msg":"hello1","seq":3}
commit msg:{"msg":"hello2","seq":4}
send msg:{"msg":"hello2","seq":4}
msg->queue2:{"msg":"hello2","seq":4}
commit msg:{"msg":"hello1","seq":5}
send msg:{"msg":"hello1","seq":5}
msg->queue2:{"msg":"hello1","seq":5}
commit msg:{"msg":"hello2","seq":6}
send msg:{"msg":"hello2","seq":6}
msg->queue2:{"msg":"hello2","seq":6}
java同步代码(synchronized)中使用BlockingQueue的更多相关文章
- wait、notify为什么要放在同步代码块中
等待方遵循的原则: 获取对象的锁,不满足条件就调用wait()方法,条件满足继续执行 通知方原则: 获取对象的锁,改变条件,然后notify 每个对象都有一个监视器锁,这个监视器锁的数据结构如下: w ...
- .NET中如何在同步代码块中调用异步方法
更新记录 本文迁移自Panda666原博客,原发布时间:2021年7月2日. 在同步代码块中调用异步方法,方法有很多. 一.对于有返回值的Task 在同步代码块中直接访问 Task 的 Result ...
- JAVA 同步之 synchronized 修饰方法
在JAVA多线程编程中,将需要并发执行的代码放在Thread类的run方法里面,然后创建多个Thread类的对象,调用start()方法,线程启动执行. 当某段代码需要互斥时,可以用 synchron ...
- java 同步代码块与同步方法
同步代码块 synchronized (obj) { // 代码块 } obj 为同步监视器,以上代码的含义为:线程开始执行同步代码块(中的代码)之前,必须先获得对同步监视器的锁定. 代码块中的代码是 ...
- Java 同步代码块 - Synchronized Blocks
java锁实现原理: http://blog.csdn.net/endlu/article/details/51249156 The synchronized keyword can be used ...
- JAVA之旅(十三)——线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this
JAVA之旅(十三)--线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this 我们继续上个篇幅接着讲线程的知识点 一.线程的安全性 当我们开启四个窗口(线程 ...
- 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁
什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...
- Java线程同步(synchronized)——卖票问题
卖票问题通常被用来举例说明线程同步问题,在Java中,采用关键字synchronized关键字来解决线程同步的问题. Java任意类型的对象都有一个标志位,该标志位具有0,1两种状态,其开始状态为1, ...
- java并发之线程同步(synchronized和锁机制)
使用synchronized实现同步方法 使用非依赖属性实现同步 在同步块中使用条件(wait(),notify(),notifyAll()) 使用锁实现同步 使用读写锁实现同步数据访问 修改锁的公平 ...
随机推荐
- 【转】从Shell脚本内部将所有标准输出及标准错误显示在屏幕并同时写入文件的方法
如果全部都要重定向的话每一条命令后面>>并不方便,可以这么做.在开头就声明 exec 1>>$log_file表示将脚本中所有的正确输出全部追加到$log_file,错误信息会 ...
- EJB开发第二期---开发具有本地接口的无状态Bean
一.EJB中的bean 1.1 EJB中bean分类 会话bean(session bean) 负责与客户端交互,是编写业务逻辑的地方,在会话bean中可以通过jdbc直接操作数据库,但大多数情况下都 ...
- idea 项目java版本选项位置
藏这里了 还有一个
- C语言和python的区别
Python可以说是目前最火的语言之一了,人工智能的兴起让Python一夜之间变得家喻户晓,Python号称目前最最简单易学的语言,现在有不少高校开始将Python作为大一新生的入门语言.本萌新也刚开 ...
- RxJS v6 学习指南
为什么要使用 RxJS RxJS 是一套处理异步编程的 API,那么我将从异步讲起. 前端编程中的异步有:事件(event).AJAX.动画(animation).定时器(timer). 异步常见的问 ...
- 新的旅程:NodeJS - 环境篇
用ASP.NET MVC好多年了,还记得当初为MVC所倡导的"DRY"理念所感染,为Razor的简单而震撼.随着MVC的成熟反而让我觉得似乎渐渐地走入了微软营造的一种高技术的牢笼. ...
- node.js学习笔记(四)——EventEmitter
error 事件 EventEmitter 定义了一个特殊的事件 error,它包含了错误的语义,我们在遇到异常的时候通常会触发 error 事件.当 error 被触发时,EventEmitter ...
- wireshark找不到网卡
在Capture Opinions中的interface若找不到网卡,一般是npf服务没有启动. npf是什么东东 Netgroup Packet Filter 网络数据包过滤器 NPF Device ...
- Linux/centos 7 使用动态ip(dhcp)切换成静态ip后无法联网的问题
确保:子网掩码,网关,dns一致,最后修改: /etc/sysconfig/network-scripts/ifcfg-ens33 查看网关和子网掩码: route -n 查看dns
- 如何基于 K8S 多租能力构建 Serverless Container
当前 Kubernetes 已经成为名副其实的企业级容器编排规范,很多云平台都开始提供兼容 Kubernetes 接口的容器服务.而在多用户支持方面,多数平台选择直接提供专属虚机集群,用户需要花费大量 ...